Mesa (master): r600g: Implement timer queries.

Alex Deucher agd5f at kemper.freedesktop.org
Tue Jan 25 19:19:51 UTC 2011


Module: Mesa
Branch: master
Commit: 90c2fd86407999475ff6accecf36e5a2c75feb9b
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=90c2fd86407999475ff6accecf36e5a2c75feb9b

Author: Mathias Fröhlich <Mathias.Froehlich at web.de>
Date:   Sun Jan 23 22:35:13 2011 +0100

r600g: Implement timer queries.

---

 src/gallium/drivers/r600/r600.h               |    1 +
 src/gallium/drivers/r600/r600_pipe.c          |    5 ++-
 src/gallium/winsys/r600/drm/r600_drm.c        |   30 +++++++++++++
 src/gallium/winsys/r600/drm/r600_hw_context.c |   55 +++++++++++++++++++------
 src/gallium/winsys/r600/drm/r600_priv.h       |    1 +
 5 files changed, 78 insertions(+), 14 deletions(-)

diff --git a/src/gallium/drivers/r600/r600.h b/src/gallium/drivers/r600/r600.h
index a852bef..b8888be 100644
--- a/src/gallium/drivers/r600/r600.h
+++ b/src/gallium/drivers/r600/r600.h
@@ -113,6 +113,7 @@ struct r600_tiling_info {
 enum radeon_family r600_get_family(struct radeon *rw);
 enum chip_class r600_get_family_class(struct radeon *radeon);
 struct r600_tiling_info *r600_get_tiling_info(struct radeon *radeon);
+unsigned r600_get_clock_crystal_freq(struct radeon *radeon);
 
 /* r600_bo.c */
 struct r600_bo;
diff --git a/src/gallium/drivers/r600/r600_pipe.c b/src/gallium/drivers/r600/r600_pipe.c
index 53d2c10..1ee327f 100644
--- a/src/gallium/drivers/r600/r600_pipe.c
+++ b/src/gallium/drivers/r600/r600_pipe.c
@@ -283,7 +283,6 @@ static int r600_get_param(struct pipe_screen* pscreen, enum pipe_cap param)
 		return 1;
 
 	/* Unsupported features (boolean caps). */
-	case PIPE_CAP_TIMER_QUERY:
 	case PIPE_CAP_STREAM_OUTPUT:
 	case PIPE_CAP_PRIMITIVE_RESTART:
 	case PIPE_CAP_INDEP_BLEND_FUNC: /* FIXME allow this */
@@ -318,6 +317,10 @@ static int r600_get_param(struct pipe_screen* pscreen, enum pipe_cap param)
 	case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER:
 		return 0;
 
+	/* Timer queries, present when the clock frequency is non zero. */
+	case PIPE_CAP_TIMER_QUERY:
+		return r600_get_clock_crystal_freq(rscreen->radeon) != 0;
+
 	default:
 		R600_ERR("r600: unknown param %d\n", param);
 		return 0;
diff --git a/src/gallium/winsys/r600/drm/r600_drm.c b/src/gallium/winsys/r600/drm/r600_drm.c
index 6fc147f..3c7e9aa 100644
--- a/src/gallium/winsys/r600/drm/r600_drm.c
+++ b/src/gallium/winsys/r600/drm/r600_drm.c
@@ -41,6 +41,10 @@
 #define RADEON_INFO_TILING_CONFIG 0x6
 #endif
 
+#ifndef RADEON_INFO_CLOCK_CRYSTAL_FREQ
+#define RADEON_INFO_CLOCK_CRYSTAL_FREQ 0x9
+#endif
+
 enum radeon_family r600_get_family(struct radeon *r600)
 {
 	return r600->family;
@@ -56,6 +60,11 @@ struct r600_tiling_info *r600_get_tiling_info(struct radeon *radeon)
 	return &radeon->tiling_info;
 }
 
+unsigned r600_get_clock_crystal_freq(struct radeon *radeon)
+{
+	return radeon->clock_crystal_freq;
+}
+
 static int radeon_get_device(struct radeon *radeon)
 {
 	struct drm_radeon_info info;
@@ -124,6 +133,24 @@ static int radeon_drm_get_tiling(struct radeon *radeon)
 	return 0;
 }
 
+static int radeon_get_clock_crystal_freq(struct radeon *radeon)
+{
+	struct drm_radeon_info info;
+	uint32_t clock_crystal_freq;
+	int r;
+
+	radeon->device = 0;
+	info.request = RADEON_INFO_CLOCK_CRYSTAL_FREQ;
+	info.value = (uintptr_t)&clock_crystal_freq;
+	r = drmCommandWriteRead(radeon->fd, DRM_RADEON_INFO, &info,
+			sizeof(struct drm_radeon_info));
+	if (r)
+		return r;
+
+	radeon->clock_crystal_freq = clock_crystal_freq;
+	return 0;
+}
+
 static int radeon_init_fence(struct radeon *radeon)
 {
 	radeon->fence = 1;
@@ -205,6 +232,9 @@ static struct radeon *radeon_new(int fd, unsigned device)
 		if (radeon_drm_get_tiling(radeon))
 			return NULL;
 	}
+	/* get the GPU counter frequency, failure is non fatal */
+	radeon_get_clock_crystal_freq(radeon);
+
 	radeon->bomgr = r600_bomgr_create(radeon, 1000000);
 	if (radeon->bomgr == NULL) {
 		return NULL;
diff --git a/src/gallium/winsys/r600/drm/r600_hw_context.c b/src/gallium/winsys/r600/drm/r600_hw_context.c
index 96e4090..6b7e4d8 100644
--- a/src/gallium/winsys/r600/drm/r600_hw_context.c
+++ b/src/gallium/winsys/r600/drm/r600_hw_context.c
@@ -1263,7 +1263,8 @@ static boolean r600_query_result(struct r600_context *ctx, struct r600_query *qu
 	for (i = 0; i < query->num_results; i += 4) {
 		start = (u64)results[i] | (u64)results[i + 1] << 32;
 		end = (u64)results[i + 2] | (u64)results[i + 3] << 32;
-		if ((start & 0x8000000000000000UL) && (end & 0x8000000000000000UL)) {
+		if (((start & 0x8000000000000000UL) && (end & 0x8000000000000000UL))
+                    || query->type == PIPE_QUERY_TIME_ELAPSED) {
 			query->result += end - start;
 		}
 	}
@@ -1275,8 +1276,15 @@ static boolean r600_query_result(struct r600_context *ctx, struct r600_query *qu
 
 void r600_query_begin(struct r600_context *ctx, struct r600_query *query)
 {
-	/* query request needs 6 dwords for begin + 6 dwords for end */
-	if ((12 + ctx->pm4_cdwords) > ctx->pm4_ndwords) {
+	unsigned required_space;
+
+	/* query request needs 6/8 dwords for begin + 6/8 dwords for end */
+	if (query->type == PIPE_QUERY_TIME_ELAPSED)
+		required_space = 16;
+	else
+		required_space = 12;
+
+	if ((required_space + ctx->pm4_cdwords) > ctx->pm4_ndwords) {
 		/* need to flush */
 		r600_context_flush(ctx);
 	}
@@ -1288,10 +1296,19 @@ void r600_query_begin(struct r600_context *ctx, struct r600_query *query)
 	}
 
 	/* emit begin query */
-	ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_EVENT_WRITE, 2);
-	ctx->pm4[ctx->pm4_cdwords++] = EVENT_TYPE(EVENT_TYPE_ZPASS_DONE) | EVENT_INDEX(1);
-	ctx->pm4[ctx->pm4_cdwords++] = query->num_results*4 + r600_bo_offset(query->buffer);
-	ctx->pm4[ctx->pm4_cdwords++] = 0;
+	if (query->type == PIPE_QUERY_TIME_ELAPSED) {
+		ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_EVENT_WRITE_EOP, 4);
+		ctx->pm4[ctx->pm4_cdwords++] = EVENT_TYPE(EVENT_TYPE_CACHE_FLUSH_AND_INV_TS_EVENT) | EVENT_INDEX(5);
+		ctx->pm4[ctx->pm4_cdwords++] = query->num_results*4 + r600_bo_offset(query->buffer);
+		ctx->pm4[ctx->pm4_cdwords++] = (3 << 29);
+		ctx->pm4[ctx->pm4_cdwords++] = 0;
+		ctx->pm4[ctx->pm4_cdwords++] = 0;
+	} else {
+		ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_EVENT_WRITE, 2);
+		ctx->pm4[ctx->pm4_cdwords++] = EVENT_TYPE(EVENT_TYPE_ZPASS_DONE) | EVENT_INDEX(1);
+		ctx->pm4[ctx->pm4_cdwords++] = query->num_results*4 + r600_bo_offset(query->buffer);
+		ctx->pm4[ctx->pm4_cdwords++] = 0;
+	}
 	ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_NOP, 0);
 	ctx->pm4[ctx->pm4_cdwords++] = 0;
 	r600_context_bo_reloc(ctx, &ctx->pm4[ctx->pm4_cdwords - 1], query->buffer);
@@ -1304,10 +1321,19 @@ void r600_query_begin(struct r600_context *ctx, struct r600_query *query)
 void r600_query_end(struct r600_context *ctx, struct r600_query *query)
 {
 	/* emit begin query */
-	ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_EVENT_WRITE, 2);
-	ctx->pm4[ctx->pm4_cdwords++] = EVENT_TYPE(EVENT_TYPE_ZPASS_DONE) | EVENT_INDEX(1);
-	ctx->pm4[ctx->pm4_cdwords++] = query->num_results*4 + 8 + r600_bo_offset(query->buffer);
-	ctx->pm4[ctx->pm4_cdwords++] = 0;
+	if (query->type == PIPE_QUERY_TIME_ELAPSED) {
+		ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_EVENT_WRITE_EOP, 4);
+		ctx->pm4[ctx->pm4_cdwords++] = EVENT_TYPE(EVENT_TYPE_CACHE_FLUSH_AND_INV_TS_EVENT) | EVENT_INDEX(5);
+		ctx->pm4[ctx->pm4_cdwords++] = query->num_results*4 + 8 + r600_bo_offset(query->buffer);
+		ctx->pm4[ctx->pm4_cdwords++] = (3 << 29);
+		ctx->pm4[ctx->pm4_cdwords++] = 0;
+		ctx->pm4[ctx->pm4_cdwords++] = 0;
+	} else {
+		ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_EVENT_WRITE, 2);
+		ctx->pm4[ctx->pm4_cdwords++] = EVENT_TYPE(EVENT_TYPE_ZPASS_DONE) | EVENT_INDEX(1);
+		ctx->pm4[ctx->pm4_cdwords++] = query->num_results*4 + 8 + r600_bo_offset(query->buffer);
+		ctx->pm4[ctx->pm4_cdwords++] = 0;
+	}
 	ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_NOP, 0);
 	ctx->pm4[ctx->pm4_cdwords++] = 0;
 	r600_context_bo_reloc(ctx, &ctx->pm4[ctx->pm4_cdwords - 1], query->buffer);
@@ -1322,7 +1348,7 @@ struct r600_query *r600_context_query_create(struct r600_context *ctx, unsigned
 {
 	struct r600_query *query;
 
-	if (query_type != PIPE_QUERY_OCCLUSION_COUNTER)
+	if (query_type != PIPE_QUERY_OCCLUSION_COUNTER && query_type != PIPE_QUERY_TIME_ELAPSED)
 		return NULL;
 
 	query = calloc(1, sizeof(struct r600_query));
@@ -1366,7 +1392,10 @@ boolean r600_context_query_result(struct r600_context *ctx,
 	}
 	if (!r600_query_result(ctx, query, wait))
 		return FALSE;
-	*result = query->result;
+	if (query->type == PIPE_QUERY_TIME_ELAPSED)
+		*result = (1000000*query->result)/r600_get_clock_crystal_freq(ctx->radeon);
+	else
+		*result = query->result;
 	query->result = 0;
 	return TRUE;
 }
diff --git a/src/gallium/winsys/r600/drm/r600_priv.h b/src/gallium/winsys/r600/drm/r600_priv.h
index a38a648..2d91cd9 100644
--- a/src/gallium/winsys/r600/drm/r600_priv.h
+++ b/src/gallium/winsys/r600/drm/r600_priv.h
@@ -49,6 +49,7 @@ struct radeon {
 	unsigned			fence;
 	unsigned			*cfence;
 	struct r600_bo			*fence_bo;
+	unsigned			clock_crystal_freq;
 };
 
 struct r600_reg {




More information about the mesa-commit mailing list