From 6eb94fc3444a300a0419c40cfcf356fdd88bc304 Mon Sep 17 00:00:00 2001 From: Vadim Girlin Date: Wed, 3 Aug 2011 01:04:19 +0400 Subject: [PATCH] r600g: use backend mask for occlusion queries 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. Note: this is a candidate for the 7.11 branch. Signed-off-by: Vadim Girlin Signed-off-by: Alex Deucher --- src/gallium/drivers/r600/r600.h | 4 + .../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 2e759c79409..2ac5ed465c1 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 98283ffbefc..7fe2050cd84 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 ab0afea5bf5..8aa8c3df52a 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 35c086ae680..30af4e8066f 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<>= 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<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<radeon, query->buffer); } diff --git a/src/gallium/winsys/r600/drm/r600_priv.h b/src/gallium/winsys/r600/drm/r600_priv.h index 69f7251c043..75115fdaed7 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. */ -- 2.30.2