From 5982a69f90d60b22715f667ce8a14cc8a04368ff Mon Sep 17 00:00:00 2001 From: Christopher Michael Date: Wed, 4 Dec 2024 06:47:16 -0500 Subject: [PATCH] v3d: Add support for time elapsed queries Add support for getting time elapsed values via glBeginQuery/glEndQuery. When recording query start & end time, we ensure that all pending jobs have been completed by using v3d cpu_queue & the multisync extension. Reviewed-by: Iago Toral Quiroga Part-of: --- src/gallium/drivers/v3d/v3d_query_pipe.c | 53 ++++++++++++++++++++---- src/gallium/drivers/v3d/v3d_screen.c | 1 + 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/gallium/drivers/v3d/v3d_query_pipe.c b/src/gallium/drivers/v3d/v3d_query_pipe.c index aa457cfa3fc..9a0ce74b3cc 100644 --- a/src/gallium/drivers/v3d/v3d_query_pipe.c +++ b/src/gallium/drivers/v3d/v3d_query_pipe.c @@ -47,7 +47,7 @@ struct v3d_query_pipe /* these fields are used for timestamp queries */ uint64_t time_result; - uint32_t sync[1]; + uint32_t sync[2]; }; static void @@ -57,6 +57,8 @@ v3d_destroy_query_pipe(struct v3d_context *v3d, struct v3d_query *query) if (pquery->sync[0]) drmSyncobjDestroy(v3d->fd, pquery->sync[0]); + if (pquery->sync[1]) + drmSyncobjDestroy(v3d->fd, pquery->sync[1]); v3d_bo_unreference(&pquery->bo); free(pquery); } @@ -97,6 +99,23 @@ v3d_begin_query_pipe(struct v3d_context *v3d, struct v3d_query *query) v3d->current_oq = pquery->bo; v3d->dirty |= V3D_DIRTY_OQ; break; + case PIPE_QUERY_TIME_ELAPSED: + /* GL_TIME_ELAPSED​: Records the time that it takes for the GPU + * to execute all of the scoped commands. + * + * The timer starts when all commands before the scope have + * completed, and the timer ends when the last scoped command + * has completed. + */ + assert(pquery->bo); + + /* flush any pending jobs */ + v3d_flush(&v3d->base); + + /* submit time elapsed query to cpu queue */ + v3d_submit_timestamp_query(&v3d->base, pquery->bo, + pquery->sync[0], 0); + break; default: unreachable("unsupported query type"); } @@ -136,6 +155,7 @@ v3d_end_query_pipe(struct v3d_context *v3d, struct v3d_query *query) v3d->dirty |= V3D_DIRTY_OQ; break; case PIPE_QUERY_TIMESTAMP: + case PIPE_QUERY_TIME_ELAPSED: /* Mesa only calls EndQuery and not BeginQuery for regular * timestamp queries * @@ -147,8 +167,12 @@ v3d_end_query_pipe(struct v3d_context *v3d, struct v3d_query *query) /* flush any pending jobs */ v3d_flush(&v3d->base); - /* submit timestamp query to cpu queue */ - v3d_submit_timestamp_query(&v3d->base, pquery->bo, pquery->sync[0], 0); + /* submit time elapsed query to cpu queue */ + uint32_t offset = pquery->type == PIPE_QUERY_TIME_ELAPSED ? + sizeof(uint64_t) : 0; + uint32_t sync = pquery->type == PIPE_QUERY_TIMESTAMP ? 0 : 1; + v3d_submit_timestamp_query(&v3d->base, pquery->bo, + pquery->sync[sync], offset); break; default: unreachable("unsupported query type"); @@ -164,17 +188,25 @@ v3d_get_query_result_pipe(struct v3d_context *v3d, struct v3d_query *query, struct v3d_query_pipe *pquery = (struct v3d_query_pipe *)query; if (pquery->bo) { - /* For timestamp queries we already flush relevant jobs - * before submitting the query */ - if (pquery->type != PIPE_QUERY_TIMESTAMP) + /* For timestamp & time elapsed queries we already flush + * relevant jobs before submitting the query */ + if (pquery->type != PIPE_QUERY_TIMESTAMP && + pquery->type != PIPE_QUERY_TIME_ELAPSED) { v3d_flush_jobs_using_bo(v3d, pquery->bo); + } if (wait) { if (!v3d_bo_wait(pquery->bo, ~0ull, "query")) return false; - assert(pquery->type != PIPE_QUERY_TIMESTAMP || + + assert((pquery->type != PIPE_QUERY_TIMESTAMP && + pquery->type != PIPE_QUERY_TIME_ELAPSED) || drmSyncobjWait(v3d->fd, &pquery->sync[0], 1, 0, 0, NULL) != -ETIME); + + assert(pquery->type != PIPE_QUERY_TIME_ELAPSED || + drmSyncobjWait(v3d->fd, &pquery->sync[1], 1, + 0, 0, NULL) != -ETIME); } else { if (!v3d_bo_wait(pquery->bo, 0, "query")) return false; @@ -183,6 +215,9 @@ v3d_get_query_result_pipe(struct v3d_context *v3d, struct v3d_query *query, if (pquery->type == PIPE_QUERY_TIMESTAMP) { uint64_t *map = v3d_bo_map(pquery->bo); pquery->time_result = *map; + } else if (pquery->type == PIPE_QUERY_TIME_ELAPSED) { + uint64_t *map = v3d_bo_map(pquery->bo); + pquery->time_result = map[1] - map[0]; } else { /* XXX: Sum up per-core values. */ uint32_t *map = v3d_bo_map(pquery->bo); @@ -208,6 +243,7 @@ v3d_get_query_result_pipe(struct v3d_context *v3d, struct v3d_query *query, vresult->u64 = pquery->end - pquery->start; break; case PIPE_QUERY_TIMESTAMP: + case PIPE_QUERY_TIME_ELAPSED: vresult->u64 = pquery->time_result; break; default: @@ -241,11 +277,14 @@ v3d_create_query_pipe(struct v3d_context *v3d, unsigned query_type, unsigned ind */ switch (pquery->type) { case PIPE_QUERY_TIMESTAMP: + case PIPE_QUERY_TIME_ELAPSED: pquery->bo = v3d_bo_alloc(v3d->screen, 4096, "query"); uint32_t *map = v3d_bo_map(pquery->bo); *map = 0; drmSyncobjCreate(v3d->fd, 0, &pquery->sync[0]); + if (pquery->type == PIPE_QUERY_TIME_ELAPSED) + drmSyncobjCreate(v3d->fd, 0, &pquery->sync[1]); break; default: break; diff --git a/src/gallium/drivers/v3d/v3d_screen.c b/src/gallium/drivers/v3d/v3d_screen.c index 40a82958795..24681e899ea 100644 --- a/src/gallium/drivers/v3d/v3d_screen.c +++ b/src/gallium/drivers/v3d/v3d_screen.c @@ -160,6 +160,7 @@ v3d_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param) case PIPE_CAP_TEXTURE_QUERY_LOD: return 1; case PIPE_CAP_QUERY_TIMESTAMP: + case PIPE_CAP_QUERY_TIME_ELAPSED: return screen->has_cpu_queue && screen->has_multisync; case PIPE_CAP_TEXTURE_SAMPLER_INDEPENDENT: return 0;