r600g: Implement timer queries.
authorMathias Fröhlich <Mathias.Froehlich@web.de>
Sun, 23 Jan 2011 21:35:13 +0000 (22:35 +0100)
committerAlex Deucher <alexdeucher@gmail.com>
Tue, 25 Jan 2011 19:18:19 +0000 (14:18 -0500)
src/gallium/drivers/r600/r600.h
src/gallium/drivers/r600/r600_pipe.c
src/gallium/winsys/r600/drm/r600_drm.c
src/gallium/winsys/r600/drm/r600_hw_context.c
src/gallium/winsys/r600/drm/r600_priv.h

index a852bef6156bfc4f215a37520f469843b6580d99..b8888bede20cb464724dbc3581894b436e3b5f7b 100644 (file)
@@ -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;
index 53d2c10c5604ac89c11be6041e6d4109fe7092cd..1ee327f16af23ca255c66de75ec6825e94b0e01c 100644 (file)
@@ -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;
index 6fc147fb6f4092c74a8ee2be6103079cd9aa1d1f..3c7e9aa4490d1381de617fb2e49fcdbf14a25377 100644 (file)
 #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;
index 96e409015c23563580adc70dc9d117eb044ebf5c..6b7e4d886f21b0cc7a0dcc1b9267fb2223e8614c 100644 (file)
@@ -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;
 }
index a38a6481b4febf8d9ed294ecb3f13e28dc8cc7f0..2d91cd97d6854bf4f13f207879b703c37688d475 100644 (file)
@@ -49,6 +49,7 @@ struct radeon {
        unsigned                        fence;
        unsigned                        *cfence;
        struct r600_bo                  *fence_bo;
+       unsigned                        clock_crystal_freq;
 };
 
 struct r600_reg {