r600_query.c revision bd25e23bf3740f59ce8859848c715daeb9e9821f
1/* 2 * Copyright 2010 Jerome Glisse <glisse@freedesktop.org> 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * on the rights to use, copy, modify, merge, publish, distribute, sub 8 * license, and/or sell copies of the Software, and to permit persons to whom 9 * the Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 * USE OR OTHER DEALINGS IN THE SOFTWARE. 22 * 23 * Authors: 24 * Jerome Glisse 25 * Corbin Simpson 26 */ 27#include <errno.h> 28#include <util/u_inlines.h> 29#include <util/u_format.h> 30#include <util/u_memory.h> 31#include "r600_screen.h" 32#include "r600_context.h" 33 34static struct radeon_state *r600_query_begin(struct r600_context *rctx, struct r600_query *rquery) 35{ 36 struct r600_screen *rscreen = rctx->screen; 37 struct radeon_state *rstate; 38 39 rstate = radeon_state(rscreen->rw, R600_QUERY_BEGIN); 40 if (rstate == NULL) 41 return NULL; 42 rstate->states[R600_QUERY__OFFSET] = rquery->num_results; 43 rstate->reloc_pm4_id[0] = R600_QUERY__BO_ID; 44 rstate->bo[0] = radeon_bo_incref(rscreen->rw, rquery->buffer); 45 rstate->nbo = 1; 46 rstate->placement[0] = RADEON_GEM_DOMAIN_GTT; 47 if (radeon_state_pm4(rstate)) { 48 radeon_state_decref(rstate); 49 return NULL; 50 } 51 return rstate; 52} 53 54static struct radeon_state *r600_query_end(struct r600_context *rctx, struct r600_query *rquery) 55{ 56 struct r600_screen *rscreen = rctx->screen; 57 struct radeon_state *rstate; 58 59 rstate = radeon_state(rscreen->rw, R600_QUERY_END); 60 if (rstate == NULL) 61 return NULL; 62 rstate->states[R600_QUERY__OFFSET] = rquery->num_results + 8; 63 rstate->reloc_pm4_id[0] = R600_QUERY__BO_ID; 64 rstate->bo[0] = radeon_bo_incref(rscreen->rw, rquery->buffer); 65 rstate->nbo = 1; 66 rstate->placement[0] = RADEON_GEM_DOMAIN_GTT; 67 if (radeon_state_pm4(rstate)) { 68 radeon_state_decref(rstate); 69 return NULL; 70 } 71 return rstate; 72} 73 74static struct pipe_query *r600_create_query(struct pipe_context *ctx, unsigned query_type) 75{ 76 struct r600_screen *rscreen = r600_screen(ctx->screen); 77 struct r600_context *rctx = r600_context(ctx); 78 struct r600_query *q; 79 80 if (query_type != PIPE_QUERY_OCCLUSION_COUNTER) 81 return NULL; 82 83 q = CALLOC_STRUCT(r600_query); 84 if (!q) 85 return NULL; 86 87 q->type = query_type; 88 LIST_ADDTAIL(&q->list, &rctx->query_list); 89 q->buffer_size = 4096; 90 91 q->buffer = radeon_bo(rscreen->rw, 0, q->buffer_size, 1, NULL); 92 if (!q->buffer) { 93 FREE(q); 94 return NULL; 95 } 96 return (struct pipe_query *)q; 97} 98 99static void r600_destroy_query(struct pipe_context *ctx, 100 struct pipe_query *query) 101{ 102 struct r600_screen *rscreen = r600_screen(ctx->screen); 103 struct r600_query *q = r600_query(query); 104 105 radeon_bo_decref(rscreen->rw, q->buffer); 106 LIST_DEL(&q->list); 107 FREE(query); 108} 109 110static void r600_query_result(struct pipe_context *ctx, struct r600_query *rquery) 111{ 112 struct r600_screen *rscreen = r600_screen(ctx->screen); 113 u64 start, end; 114 u32 *results; 115 int i; 116 117 radeon_bo_wait(rscreen->rw, rquery->buffer); 118 radeon_bo_map(rscreen->rw, rquery->buffer); 119 results = rquery->buffer->data; 120 for (i = 0; i < rquery->num_results; i += 4) { 121 start = (u64)results[i] | (u64)results[i + 1] << 32; 122 end = (u64)results[i + 2] | (u64)results[i + 3] << 32; 123 if ((start & 0x8000000000000000UL) && (end & 0x8000000000000000UL)) { 124 rquery->result += end - start; 125 } 126 } 127 radeon_bo_unmap(rscreen->rw, rquery->buffer); 128 rquery->num_results = 0; 129} 130 131static void r600_query_resume(struct pipe_context *ctx, struct r600_query *rquery) 132{ 133 struct r600_context *rctx = r600_context(ctx); 134 135 if (rquery->num_results >= ((rquery->buffer_size >> 2) - 2)) { 136 /* running out of space */ 137 if (!rquery->flushed) { 138 ctx->flush(ctx, 0, NULL); 139 } 140 r600_query_result(ctx, rquery); 141 } 142 rquery->rstate = radeon_state_decref(rquery->rstate); 143 rquery->rstate = r600_query_begin(rctx, rquery); 144 rquery->flushed = false; 145} 146 147static void r600_query_suspend(struct pipe_context *ctx, struct r600_query *rquery) 148{ 149 struct r600_context *rctx = r600_context(ctx); 150 151 rquery->rstate = radeon_state_decref(rquery->rstate); 152 rquery->rstate = r600_query_end(rctx, rquery); 153 rquery->num_results += 16; 154} 155 156static void r600_begin_query(struct pipe_context *ctx, struct pipe_query *query) 157{ 158 struct r600_context *rctx = r600_context(ctx); 159 struct r600_query *rquery = r600_query(query); 160 int r; 161 162 rquery->state = R600_QUERY_STATE_STARTED; 163 rquery->num_results = 0; 164 rquery->flushed = false; 165 r600_query_resume(ctx, rquery); 166 r = radeon_ctx_set_query_state(rctx->ctx, rquery->rstate); 167 if (r == -EBUSY) { 168 /* this shouldn't happen */ 169 R600_ERR("had to flush while emitting end query\n"); 170 ctx->flush(ctx, 0, NULL); 171 r = radeon_ctx_set_query_state(rctx->ctx, rquery->rstate); 172 } 173} 174 175static void r600_end_query(struct pipe_context *ctx, struct pipe_query *query) 176{ 177 struct r600_context *rctx = r600_context(ctx); 178 struct r600_query *rquery = r600_query(query); 179 int r; 180 181 rquery->state &= ~R600_QUERY_STATE_STARTED; 182 rquery->state |= R600_QUERY_STATE_ENDED; 183 r600_query_suspend(ctx, rquery); 184 r = radeon_ctx_set_query_state(rctx->ctx, rquery->rstate); 185 if (r == -EBUSY) { 186 /* this shouldn't happen */ 187 R600_ERR("had to flush while emitting end query\n"); 188 ctx->flush(ctx, 0, NULL); 189 r = radeon_ctx_set_query_state(rctx->ctx, rquery->rstate); 190 } 191} 192 193void r600_queries_suspend(struct pipe_context *ctx) 194{ 195 struct r600_context *rctx = r600_context(ctx); 196 struct r600_query *rquery; 197 int r; 198 199 LIST_FOR_EACH_ENTRY(rquery, &rctx->query_list, list) { 200 if (rquery->state & R600_QUERY_STATE_STARTED) { 201 r600_query_suspend(ctx, rquery); 202 r = radeon_ctx_set_query_state(rctx->ctx, rquery->rstate); 203 if (r == -EBUSY) { 204 /* this shouldn't happen */ 205 R600_ERR("had to flush while emitting end query\n"); 206 ctx->flush(ctx, 0, NULL); 207 r = radeon_ctx_set_query_state(rctx->ctx, rquery->rstate); 208 } 209 } 210 rquery->state |= R600_QUERY_STATE_SUSPENDED; 211 } 212} 213 214void r600_queries_resume(struct pipe_context *ctx) 215{ 216 struct r600_context *rctx = r600_context(ctx); 217 struct r600_query *rquery; 218 int r; 219 220 LIST_FOR_EACH_ENTRY(rquery, &rctx->query_list, list) { 221 if (rquery->state & R600_QUERY_STATE_STARTED) { 222 r600_query_resume(ctx, rquery); 223 r = radeon_ctx_set_query_state(rctx->ctx, rquery->rstate); 224 if (r == -EBUSY) { 225 /* this shouldn't happen */ 226 R600_ERR("had to flush while emitting end query\n"); 227 ctx->flush(ctx, 0, NULL); 228 r = radeon_ctx_set_query_state(rctx->ctx, rquery->rstate); 229 } 230 } 231 rquery->state &= ~R600_QUERY_STATE_SUSPENDED; 232 } 233} 234 235static boolean r600_get_query_result(struct pipe_context *ctx, 236 struct pipe_query *query, 237 boolean wait, void *vresult) 238{ 239 struct r600_query *rquery = r600_query(query); 240 uint64_t *result = (uint64_t*)vresult; 241 242 if (!rquery->flushed) { 243 ctx->flush(ctx, 0, NULL); 244 rquery->flushed = true; 245 } 246 r600_query_result(ctx, rquery); 247 *result = rquery->result; 248 rquery->result = 0; 249 return TRUE; 250} 251 252void r600_init_query_functions(struct r600_context* rctx) 253{ 254 LIST_INITHEAD(&rctx->query_list); 255 256 rctx->context.create_query = r600_create_query; 257 rctx->context.destroy_query = r600_destroy_query; 258 rctx->context.begin_query = r600_begin_query; 259 rctx->context.end_query = r600_end_query; 260 rctx->context.get_query_result = r600_get_query_result; 261} 262