r600g: Added DB_SHADER_CONTROL defines.
[mesa.git] / src / gallium / drivers / r600 / r600_query.c
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
34 static void r600_query_begin(struct r600_context *rctx, struct r600_query *rquery)
35 {
36 struct r600_screen *rscreen = rctx->screen;
37 struct radeon_state *rstate = &rquery->rstate;
38
39 radeon_state_fini(rstate);
40 radeon_state_init(rstate, rscreen->rw, R600_STATE_QUERY_BEGIN, 0, 0);
41 rstate->states[R600_QUERY__OFFSET] = rquery->num_results;
42 radeon_ws_bo_reference(rscreen->rw, &rstate->bo[0], rquery->buffer);
43 rstate->nbo = 1;
44 rstate->placement[0] = RADEON_GEM_DOMAIN_GTT;
45 if (radeon_state_pm4(rstate)) {
46 radeon_state_fini(rstate);
47 }
48 }
49
50 static void r600_query_end(struct r600_context *rctx, struct r600_query *rquery)
51 {
52 struct r600_screen *rscreen = rctx->screen;
53 struct radeon_state *rstate = &rquery->rstate;
54
55 radeon_state_fini(rstate);
56 radeon_state_init(rstate, rscreen->rw, R600_STATE_QUERY_END, 0, 0);
57 rstate->states[R600_QUERY__OFFSET] = rquery->num_results + 8;
58 radeon_ws_bo_reference(rscreen->rw, &rstate->bo[0], rquery->buffer);
59 rstate->nbo = 1;
60 rstate->placement[0] = RADEON_GEM_DOMAIN_GTT;
61 if (radeon_state_pm4(rstate)) {
62 radeon_state_fini(rstate);
63 }
64 }
65
66 static struct pipe_query *r600_create_query(struct pipe_context *ctx, unsigned query_type)
67 {
68 struct r600_screen *rscreen = r600_screen(ctx->screen);
69 struct r600_context *rctx = r600_context(ctx);
70 struct r600_query *q;
71
72 if (query_type != PIPE_QUERY_OCCLUSION_COUNTER)
73 return NULL;
74
75 q = CALLOC_STRUCT(r600_query);
76 if (!q)
77 return NULL;
78
79 q->type = query_type;
80 q->buffer_size = 4096;
81
82 q->buffer = radeon_ws_bo(rscreen->rw, q->buffer_size, 1, 0);
83 if (!q->buffer) {
84 FREE(q);
85 return NULL;
86 }
87
88 LIST_ADDTAIL(&q->list, &rctx->query_list);
89
90 return (struct pipe_query *)q;
91 }
92
93 static void r600_destroy_query(struct pipe_context *ctx,
94 struct pipe_query *query)
95 {
96 struct r600_screen *rscreen = r600_screen(ctx->screen);
97 struct r600_query *q = r600_query(query);
98
99 radeon_ws_bo_reference(rscreen->rw, &q->buffer, NULL);
100 LIST_DEL(&q->list);
101 FREE(query);
102 }
103
104 static void r600_query_result(struct pipe_context *ctx, struct r600_query *rquery)
105 {
106 struct r600_screen *rscreen = r600_screen(ctx->screen);
107 u64 start, end;
108 u32 *results;
109 int i;
110
111 radeon_ws_bo_wait(rscreen->rw, rquery->buffer);
112 results = radeon_ws_bo_map(rscreen->rw, rquery->buffer, 0, r600_context(ctx));
113 for (i = 0; i < rquery->num_results; i += 4) {
114 start = (u64)results[i] | (u64)results[i + 1] << 32;
115 end = (u64)results[i + 2] | (u64)results[i + 3] << 32;
116 if ((start & 0x8000000000000000UL) && (end & 0x8000000000000000UL)) {
117 rquery->result += end - start;
118 }
119 }
120 radeon_ws_bo_unmap(rscreen->rw, rquery->buffer);
121 rquery->num_results = 0;
122 }
123
124 static void r600_query_resume(struct pipe_context *ctx, struct r600_query *rquery)
125 {
126 struct r600_context *rctx = r600_context(ctx);
127
128 if (rquery->num_results >= ((rquery->buffer_size >> 2) - 2)) {
129 /* running out of space */
130 if (!rquery->flushed) {
131 ctx->flush(ctx, 0, NULL);
132 }
133 r600_query_result(ctx, rquery);
134 }
135 r600_query_begin(rctx, rquery);
136 rquery->flushed = false;
137 }
138
139 static void r600_query_suspend(struct pipe_context *ctx, struct r600_query *rquery)
140 {
141 struct r600_context *rctx = r600_context(ctx);
142
143 r600_query_end(rctx, rquery);
144 rquery->num_results += 16;
145 }
146
147 static void r600_begin_query(struct pipe_context *ctx, struct pipe_query *query)
148 {
149 struct r600_context *rctx = r600_context(ctx);
150 struct r600_query *rquery = r600_query(query);
151 int r;
152
153 rquery->state = R600_QUERY_STATE_STARTED;
154 rquery->num_results = 0;
155 rquery->flushed = false;
156 r600_query_resume(ctx, rquery);
157 r = radeon_ctx_set_query_state(rctx->ctx, &rquery->rstate);
158 if (r == -EBUSY) {
159 /* this shouldn't happen */
160 R600_ERR("had to flush while emitting end query\n");
161 ctx->flush(ctx, 0, NULL);
162 r = radeon_ctx_set_query_state(rctx->ctx, &rquery->rstate);
163 }
164 }
165
166 static void r600_end_query(struct pipe_context *ctx, struct pipe_query *query)
167 {
168 struct r600_context *rctx = r600_context(ctx);
169 struct r600_query *rquery = r600_query(query);
170 int r;
171
172 rquery->state &= ~R600_QUERY_STATE_STARTED;
173 rquery->state |= R600_QUERY_STATE_ENDED;
174 r600_query_suspend(ctx, rquery);
175 r = radeon_ctx_set_query_state(rctx->ctx, &rquery->rstate);
176 if (r == -EBUSY) {
177 /* this shouldn't happen */
178 R600_ERR("had to flush while emitting end query\n");
179 ctx->flush(ctx, 0, NULL);
180 r = radeon_ctx_set_query_state(rctx->ctx, &rquery->rstate);
181 }
182 }
183
184 void r600_queries_suspend(struct pipe_context *ctx)
185 {
186 struct r600_context *rctx = r600_context(ctx);
187 struct r600_query *rquery;
188 int r;
189
190 LIST_FOR_EACH_ENTRY(rquery, &rctx->query_list, list) {
191 if (rquery->state & R600_QUERY_STATE_STARTED) {
192 r600_query_suspend(ctx, rquery);
193 r = radeon_ctx_set_query_state(rctx->ctx, &rquery->rstate);
194 if (r == -EBUSY) {
195 /* this shouldn't happen */
196 R600_ERR("had to flush while emitting end query\n");
197 ctx->flush(ctx, 0, NULL);
198 r = radeon_ctx_set_query_state(rctx->ctx, &rquery->rstate);
199 }
200 }
201 rquery->state |= R600_QUERY_STATE_SUSPENDED;
202 }
203 }
204
205 void r600_queries_resume(struct pipe_context *ctx)
206 {
207 struct r600_context *rctx = r600_context(ctx);
208 struct r600_query *rquery;
209 int r;
210
211 LIST_FOR_EACH_ENTRY(rquery, &rctx->query_list, list) {
212 if (rquery->state & R600_QUERY_STATE_STARTED) {
213 r600_query_resume(ctx, rquery);
214 r = radeon_ctx_set_query_state(rctx->ctx, &rquery->rstate);
215 if (r == -EBUSY) {
216 /* this shouldn't happen */
217 R600_ERR("had to flush while emitting end query\n");
218 ctx->flush(ctx, 0, NULL);
219 r = radeon_ctx_set_query_state(rctx->ctx, &rquery->rstate);
220 }
221 }
222 rquery->state &= ~R600_QUERY_STATE_SUSPENDED;
223 }
224 }
225
226 static boolean r600_get_query_result(struct pipe_context *ctx,
227 struct pipe_query *query,
228 boolean wait, void *vresult)
229 {
230 struct r600_query *rquery = r600_query(query);
231 uint64_t *result = (uint64_t*)vresult;
232
233 if (!rquery->flushed) {
234 ctx->flush(ctx, 0, NULL);
235 rquery->flushed = true;
236 }
237 r600_query_result(ctx, rquery);
238 *result = rquery->result;
239 rquery->result = 0;
240 return TRUE;
241 }
242
243 void r600_init_query_functions(struct r600_context* rctx)
244 {
245 LIST_INITHEAD(&rctx->query_list);
246
247 rctx->context.create_query = r600_create_query;
248 rctx->context.destroy_query = r600_destroy_query;
249 rctx->context.begin_query = r600_begin_query;
250 rctx->context.end_query = r600_end_query;
251 rctx->context.get_query_result = r600_get_query_result;
252 }