[Mesa-dev] [PATCH v5] r600g: use backend mask for occlusion queries

Vadim Girlin vadimgirlin at gmail.com
Tue Aug 2 14:04:19 PDT 2011


Use backend_map kernel query if supported, otherwise analyze ZPASS_DONE
results to get the mask.

Fixes lockups with predicated rendering due to incorrect query buffer
initialization on some cards.

Signed-off-by: Vadim Girlin <vadimgirlin at gmail.com>
---

Updated with r600_bo_offset removal.

 src/gallium/drivers/r600/r600.h                    |    4 +
 src/gallium/winsys/r600/drm/evergreen_hw_context.c |    2 +
 src/gallium/winsys/r600/drm/r600_drm.c             |   59 ++++++++++++
 src/gallium/winsys/r600/drm/r600_hw_context.c      |   96 +++++++++++++++++++-
 src/gallium/winsys/r600/drm/r600_priv.h            |    3 +
 5 files changed, 160 insertions(+), 4 deletions(-)

diff --git a/src/gallium/drivers/r600/r600.h b/src/gallium/drivers/r600/r600.h
index 2e759c7..2ac5ed4 100644
--- a/src/gallium/drivers/r600/r600.h
+++ b/src/gallium/drivers/r600/r600.h
@@ -94,6 +94,8 @@ struct r600_tiling_info *r600_get_tiling_info(struct radeon *radeon);
 unsigned r600_get_clock_crystal_freq(struct radeon *radeon);
 unsigned r600_get_minor_version(struct radeon *radeon);
 unsigned r600_get_num_backends(struct radeon *radeon);
+unsigned r600_get_num_tile_pipes(struct radeon *radeon);
+unsigned r600_get_backend_map(struct radeon *radeon);
 
 /* r600_bo.c */
 struct r600_bo;
@@ -258,6 +260,7 @@ struct r600_context {
 	u32			*pm4;
 	struct list_head	query_list;
 	unsigned		num_query_running;
+	unsigned		backend_mask;
 	struct list_head	fenced_bo;
 	unsigned                max_db; /* for OQ */
 	unsigned                num_dest_buffers;
@@ -279,6 +282,7 @@ struct r600_draw {
 	struct r600_bo		*indices;
 };
 
+void r600_get_backend_mask(struct r600_context *ctx);
 int r600_context_init(struct r600_context *ctx, struct radeon *radeon);
 void r600_context_fini(struct r600_context *ctx);
 void r600_context_pipe_state_set(struct r600_context *ctx, struct r600_pipe_state *state);
diff --git a/src/gallium/winsys/r600/drm/evergreen_hw_context.c b/src/gallium/winsys/r600/drm/evergreen_hw_context.c
index 98283ff..7fe2050 100644
--- a/src/gallium/winsys/r600/drm/evergreen_hw_context.c
+++ b/src/gallium/winsys/r600/drm/evergreen_hw_context.c
@@ -1018,6 +1018,8 @@ int evergreen_context_init(struct r600_context *ctx, struct radeon *radeon)
 
 	LIST_INITHEAD(&ctx->fenced_bo);
 
+	r600_get_backend_mask(ctx);
+
 	return 0;
 out_err:
 	r600_context_fini(ctx);
diff --git a/src/gallium/winsys/r600/drm/r600_drm.c b/src/gallium/winsys/r600/drm/r600_drm.c
index ab0afea..8aa8c3d 100644
--- a/src/gallium/winsys/r600/drm/r600_drm.c
+++ b/src/gallium/winsys/r600/drm/r600_drm.c
@@ -50,6 +50,14 @@
 #define RADEON_INFO_NUM_BACKENDS 0xa
 #endif
 
+#ifndef RADEON_INFO_NUM_TILE_PIPES
+#define RADEON_INFO_NUM_TILE_PIPES 0xb
+#endif
+
+#ifndef RADEON_INFO_BACKEND_MAP
+#define RADEON_INFO_BACKEND_MAP 0xd
+#endif
+
 enum radeon_family r600_get_family(struct radeon *r600)
 {
 	return r600->family;
@@ -75,6 +83,16 @@ unsigned r600_get_num_backends(struct radeon *radeon)
 	return radeon->num_backends;
 }
 
+unsigned r600_get_num_tile_pipes(struct radeon *radeon)
+{
+	return radeon->num_tile_pipes;
+}
+
+unsigned r600_get_backend_map(struct radeon *radeon)
+{
+	return radeon->backend_map;
+}
+
 unsigned r600_get_minor_version(struct radeon *radeon)
 {
 	return radeon->minor_version;
@@ -241,6 +259,42 @@ static int radeon_get_num_backends(struct radeon *radeon)
 	return 0;
 }
 
+static int radeon_get_num_tile_pipes(struct radeon *radeon)
+{
+	struct drm_radeon_info info = {};
+	uint32_t num_tile_pipes = 0;
+	int r;
+
+	info.request = RADEON_INFO_NUM_TILE_PIPES;
+	info.value = (uintptr_t)&num_tile_pipes;
+	r = drmCommandWriteRead(radeon->fd, DRM_RADEON_INFO, &info,
+			sizeof(struct drm_radeon_info));
+	if (r)
+		return r;
+
+	radeon->num_tile_pipes = num_tile_pipes;
+	return 0;
+}
+
+static int radeon_get_backend_map(struct radeon *radeon)
+{
+	struct drm_radeon_info info = {};
+	uint32_t backend_map = 0;
+	int r;
+
+	info.request = RADEON_INFO_BACKEND_MAP;
+	info.value = (uintptr_t)&backend_map;
+	r = drmCommandWriteRead(radeon->fd, DRM_RADEON_INFO, &info,
+			sizeof(struct drm_radeon_info));
+	if (r)
+		return r;
+
+	radeon->backend_map = backend_map;
+	radeon->backend_map_valid = TRUE;
+
+	return 0;
+}
+
 
 static int radeon_init_fence(struct radeon *radeon)
 {
@@ -362,6 +416,11 @@ static struct radeon *radeon_new(int fd, unsigned device)
 	if (radeon->minor_version >= 9)
 		radeon_get_num_backends(radeon);
 
+	if (radeon->minor_version >= 11) {
+		radeon_get_num_tile_pipes(radeon);
+		radeon_get_backend_map(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 35c086a..30af4e8 100644
--- a/src/gallium/winsys/r600/drm/r600_hw_context.c
+++ b/src/gallium/winsys/r600/drm/r600_hw_context.c
@@ -39,6 +39,91 @@
 
 #define GROUP_FORCE_NEW_BLOCK	0
 
+/* Get backends mask */
+void r600_get_backend_mask(struct r600_context *ctx)
+{
+	struct r600_bo * buffer;
+	u32 * results;
+	unsigned num_backends = r600_get_num_backends(ctx->radeon);
+	unsigned i, mask = 0;
+
+	/* if backend_map query is supported by the kernel */
+	if (ctx->radeon->backend_map_valid) {
+		unsigned num_tile_pipes = r600_get_num_tile_pipes(ctx->radeon);
+		unsigned backend_map = r600_get_backend_map(ctx->radeon);
+		unsigned item_width, item_mask;
+
+		if (ctx->radeon->chip_class >= EVERGREEN) {
+			item_width = 4;
+			item_mask = 0x7;
+		} else {
+			item_width = 2;
+			item_mask = 0x3;
+		}
+
+		while(num_tile_pipes--) {
+			i = backend_map & item_mask;
+			mask |= (1<<i);
+			backend_map >>= item_width;
+		}
+		if (mask != 0) {
+			ctx->backend_mask = mask;
+			return;
+		}
+	}
+
+	/* otherwise backup path for older kernels */
+
+	/* create buffer for event data */
+	buffer = r600_bo(ctx->radeon, ctx->max_db*16, 1, 0,
+				PIPE_USAGE_STAGING);
+	if (!buffer)
+		goto err;
+
+	/* initialize buffer with zeroes */
+	results = r600_bo_map(ctx->radeon, buffer, PB_USAGE_CPU_WRITE, NULL);
+	if (results) {
+		memset(results, 0, ctx->max_db * 4 * 4);
+		r600_bo_unmap(ctx->radeon, buffer);
+
+		/* emit EVENT_WRITE for ZPASS_DONE */
+		ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_EVENT_WRITE, 2, 0);
+		ctx->pm4[ctx->pm4_cdwords++] = EVENT_TYPE(EVENT_TYPE_ZPASS_DONE) | EVENT_INDEX(1);
+		ctx->pm4[ctx->pm4_cdwords++] = 0;
+		ctx->pm4[ctx->pm4_cdwords++] = 0;
+
+		ctx->pm4[ctx->pm4_cdwords++] = PKT3(PKT3_NOP, 0, 0);
+		ctx->pm4[ctx->pm4_cdwords++] = 0;
+		r600_context_bo_reloc(ctx, &ctx->pm4[ctx->pm4_cdwords - 1], buffer);
+
+		/* execute */
+		r600_context_flush(ctx);
+
+		/* analyze results */
+		results = r600_bo_map(ctx->radeon, buffer, PB_USAGE_CPU_READ, NULL);
+		if (results) {
+			for(i = 0; i < ctx->max_db; i++) {
+				/* at least highest bit will be set if backend is used */
+				if (results[i*4 + 1])
+					mask |= (1<<i);
+			}
+			r600_bo_unmap(ctx->radeon, buffer);
+		}
+	}
+
+	r600_bo_reference(ctx->radeon, &buffer, NULL);
+
+	if (mask != 0) {
+		ctx->backend_mask = mask;
+		return;
+	}
+
+err:
+	/* fallback to old method - set num_backends lower bits to 1 */
+	ctx->backend_mask = (~((u32)0))>>(32-num_backends);
+	return;
+}
+
 static inline void r600_context_ps_partial_flush(struct r600_context *ctx)
 {
 	if (!(ctx->flags & R600_CONTEXT_DRAW_PENDING))
@@ -898,6 +983,8 @@ int r600_context_init(struct r600_context *ctx, struct radeon *radeon)
 
 	ctx->max_db = 4;
 
+	r600_get_backend_mask(ctx);
+
 	return 0;
 out_err:
 	r600_context_fini(ctx);
@@ -1652,7 +1739,6 @@ 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)
 {
 	unsigned required_space, new_results_end;
-	int num_backends = r600_get_num_backends(ctx->radeon);
 
 	/* query request needs 6/8 dwords for begin + 6/8 dwords for end */
 	if (query->type == PIPE_QUERY_TIME_ELAPSED)
@@ -1698,9 +1784,11 @@ void r600_query_begin(struct r600_context *ctx, struct r600_query *query)
 			memset(results, 0, query->result_size);
 
 			/* Set top bits for unused backends */
-			for (i = num_backends; i < ctx->max_db; i++) {
-				results[(i * 4)+1] = 0x80000000;
-				results[(i * 4)+3] = 0x80000000;
+			for (i = 0; i < ctx->max_db; i++) {
+				if (!(ctx->backend_mask & (1<<i))) {
+					results[(i * 4)+1] = 0x80000000;
+					results[(i * 4)+3] = 0x80000000;
+				}
 			}
 			r600_bo_unmap(ctx->radeon, query->buffer);
 		}
diff --git a/src/gallium/winsys/r600/drm/r600_priv.h b/src/gallium/winsys/r600/drm/r600_priv.h
index 69f7251..75115fd 100644
--- a/src/gallium/winsys/r600/drm/r600_priv.h
+++ b/src/gallium/winsys/r600/drm/r600_priv.h
@@ -55,6 +55,9 @@ struct radeon {
 	struct r600_bo			*fence_bo;
 	unsigned			clock_crystal_freq;
 	unsigned			num_backends;
+	unsigned			num_tile_pipes;
+	unsigned			backend_map;
+	boolean				backend_map_valid;
 	unsigned                        minor_version;
 
         /* List of buffer handles and its mutex. */
-- 
1.7.6



More information about the mesa-dev mailing list