2 * Copyright 2010 Jerome Glisse <glisse@freedesktop.org>
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:
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
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.
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"
34 static void r600_query_begin(struct r600_context
*rctx
, struct r600_query
*rquery
)
36 struct r600_screen
*rscreen
= rctx
->screen
;
37 struct radeon_state
*rstate
= &rquery
->rstate
;
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
);
44 rstate
->placement
[0] = RADEON_GEM_DOMAIN_GTT
;
45 if (radeon_state_pm4(rstate
)) {
46 radeon_state_fini(rstate
);
50 static void r600_query_end(struct r600_context
*rctx
, struct r600_query
*rquery
)
52 struct r600_screen
*rscreen
= rctx
->screen
;
53 struct radeon_state
*rstate
= &rquery
->rstate
;
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
);
60 rstate
->placement
[0] = RADEON_GEM_DOMAIN_GTT
;
61 if (radeon_state_pm4(rstate
)) {
62 radeon_state_fini(rstate
);
66 static struct pipe_query
*r600_create_query(struct pipe_context
*ctx
, unsigned query_type
)
68 struct r600_screen
*rscreen
= r600_screen(ctx
->screen
);
69 struct r600_context
*rctx
= r600_context(ctx
);
72 if (query_type
!= PIPE_QUERY_OCCLUSION_COUNTER
)
75 q
= CALLOC_STRUCT(r600_query
);
80 q
->buffer_size
= 4096;
82 q
->buffer
= radeon_ws_bo(rscreen
->rw
, q
->buffer_size
, 1, 0);
88 LIST_ADDTAIL(&q
->list
, &rctx
->query_list
);
90 return (struct pipe_query
*)q
;
93 static void r600_destroy_query(struct pipe_context
*ctx
,
94 struct pipe_query
*query
)
96 struct r600_screen
*rscreen
= r600_screen(ctx
->screen
);
97 struct r600_query
*q
= r600_query(query
);
99 radeon_ws_bo_reference(rscreen
->rw
, &q
->buffer
, NULL
);
104 static void r600_query_result(struct pipe_context
*ctx
, struct r600_query
*rquery
)
106 struct r600_screen
*rscreen
= r600_screen(ctx
->screen
);
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
;
120 radeon_ws_bo_unmap(rscreen
->rw
, rquery
->buffer
);
121 rquery
->num_results
= 0;
124 static void r600_query_resume(struct pipe_context
*ctx
, struct r600_query
*rquery
)
126 struct r600_context
*rctx
= r600_context(ctx
);
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
);
133 r600_query_result(ctx
, rquery
);
135 r600_query_begin(rctx
, rquery
);
136 rquery
->flushed
= false;
139 static void r600_query_suspend(struct pipe_context
*ctx
, struct r600_query
*rquery
)
141 struct r600_context
*rctx
= r600_context(ctx
);
143 r600_query_end(rctx
, rquery
);
144 rquery
->num_results
+= 16;
147 static void r600_begin_query(struct pipe_context
*ctx
, struct pipe_query
*query
)
149 struct r600_context
*rctx
= r600_context(ctx
);
150 struct r600_query
*rquery
= r600_query(query
);
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
);
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
);
166 static void r600_end_query(struct pipe_context
*ctx
, struct pipe_query
*query
)
168 struct r600_context
*rctx
= r600_context(ctx
);
169 struct r600_query
*rquery
= r600_query(query
);
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
);
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
);
184 void r600_queries_suspend(struct pipe_context
*ctx
)
186 struct r600_context
*rctx
= r600_context(ctx
);
187 struct r600_query
*rquery
;
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
);
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
);
201 rquery
->state
|= R600_QUERY_STATE_SUSPENDED
;
205 void r600_queries_resume(struct pipe_context
*ctx
)
207 struct r600_context
*rctx
= r600_context(ctx
);
208 struct r600_query
*rquery
;
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
);
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
);
222 rquery
->state
&= ~R600_QUERY_STATE_SUSPENDED
;
226 static boolean
r600_get_query_result(struct pipe_context
*ctx
,
227 struct pipe_query
*query
,
228 boolean wait
, void *vresult
)
230 struct r600_query
*rquery
= r600_query(query
);
231 uint64_t *result
= (uint64_t*)vresult
;
233 if (!rquery
->flushed
) {
234 ctx
->flush(ctx
, 0, NULL
);
235 rquery
->flushed
= true;
237 r600_query_result(ctx
, rquery
);
238 *result
= rquery
->result
;
243 void r600_init_query_functions(struct r600_context
* rctx
)
245 LIST_INITHEAD(&rctx
->query_list
);
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
;