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 results
= radeon_ws_bo_map(rscreen
->rw
, rquery
->buffer
, 0, ctx
);
112 for (i
= 0; i
< rquery
->num_results
; i
+= 4) {
113 start
= (u64
)results
[i
] | (u64
)results
[i
+ 1] << 32;
114 end
= (u64
)results
[i
+ 2] | (u64
)results
[i
+ 3] << 32;
115 if ((start
& 0x8000000000000000UL
) && (end
& 0x8000000000000000UL
)) {
116 rquery
->result
+= end
- start
;
119 radeon_ws_bo_unmap(rscreen
->rw
, rquery
->buffer
);
120 rquery
->num_results
= 0;
123 static void r600_query_resume(struct pipe_context
*ctx
, struct r600_query
*rquery
)
125 struct r600_context
*rctx
= r600_context(ctx
);
127 if (rquery
->num_results
>= ((rquery
->buffer_size
>> 2) - 2)) {
128 /* running out of space */
129 if (!rquery
->flushed
) {
130 ctx
->flush(ctx
, 0, NULL
);
132 r600_query_result(ctx
, rquery
);
134 r600_query_begin(rctx
, rquery
);
135 rquery
->flushed
= FALSE
;
138 static void r600_query_suspend(struct pipe_context
*ctx
, struct r600_query
*rquery
)
140 struct r600_context
*rctx
= r600_context(ctx
);
142 r600_query_end(rctx
, rquery
);
143 rquery
->num_results
+= 16;
146 static void r600_begin_query(struct pipe_context
*ctx
, struct pipe_query
*query
)
148 struct r600_context
*rctx
= r600_context(ctx
);
149 struct r600_query
*rquery
= r600_query(query
);
152 rquery
->state
= R600_QUERY_STATE_STARTED
;
153 rquery
->num_results
= 0;
154 rquery
->flushed
= FALSE
;
155 r600_query_resume(ctx
, rquery
);
156 r
= radeon_ctx_set_query_state(rctx
->ctx
, &rquery
->rstate
);
158 /* this shouldn't happen */
159 R600_ERR("had to flush while emitting end query\n");
160 ctx
->flush(ctx
, 0, NULL
);
161 r
= radeon_ctx_set_query_state(rctx
->ctx
, &rquery
->rstate
);
165 static void r600_end_query(struct pipe_context
*ctx
, struct pipe_query
*query
)
167 struct r600_context
*rctx
= r600_context(ctx
);
168 struct r600_query
*rquery
= r600_query(query
);
171 rquery
->state
&= ~R600_QUERY_STATE_STARTED
;
172 rquery
->state
|= R600_QUERY_STATE_ENDED
;
173 r600_query_suspend(ctx
, rquery
);
174 r
= radeon_ctx_set_query_state(rctx
->ctx
, &rquery
->rstate
);
176 /* this shouldn't happen */
177 R600_ERR("had to flush while emitting end query\n");
178 ctx
->flush(ctx
, 0, NULL
);
179 r
= radeon_ctx_set_query_state(rctx
->ctx
, &rquery
->rstate
);
183 void r600_queries_suspend(struct pipe_context
*ctx
)
185 struct r600_context
*rctx
= r600_context(ctx
);
186 struct r600_query
*rquery
;
189 LIST_FOR_EACH_ENTRY(rquery
, &rctx
->query_list
, list
) {
190 if (rquery
->state
& R600_QUERY_STATE_STARTED
) {
191 r600_query_suspend(ctx
, rquery
);
192 r
= radeon_ctx_set_query_state(rctx
->ctx
, &rquery
->rstate
);
194 /* this shouldn't happen */
195 R600_ERR("had to flush while emitting end query\n");
196 ctx
->flush(ctx
, 0, NULL
);
197 r
= radeon_ctx_set_query_state(rctx
->ctx
, &rquery
->rstate
);
200 rquery
->state
|= R600_QUERY_STATE_SUSPENDED
;
204 void r600_queries_resume(struct pipe_context
*ctx
)
206 struct r600_context
*rctx
= r600_context(ctx
);
207 struct r600_query
*rquery
;
210 LIST_FOR_EACH_ENTRY(rquery
, &rctx
->query_list
, list
) {
211 if (rquery
->state
& R600_QUERY_STATE_STARTED
) {
212 r600_query_resume(ctx
, rquery
);
213 r
= radeon_ctx_set_query_state(rctx
->ctx
, &rquery
->rstate
);
215 /* this shouldn't happen */
216 R600_ERR("had to flush while emitting end query\n");
217 ctx
->flush(ctx
, 0, NULL
);
218 r
= radeon_ctx_set_query_state(rctx
->ctx
, &rquery
->rstate
);
221 rquery
->state
&= ~R600_QUERY_STATE_SUSPENDED
;
225 static boolean
r600_get_query_result(struct pipe_context
*ctx
,
226 struct pipe_query
*query
,
227 boolean wait
, void *vresult
)
229 struct r600_query
*rquery
= r600_query(query
);
230 uint64_t *result
= (uint64_t*)vresult
;
232 if (!rquery
->flushed
) {
233 ctx
->flush(ctx
, 0, NULL
);
234 rquery
->flushed
= TRUE
;
236 r600_query_result(ctx
, rquery
);
237 *result
= rquery
->result
;
242 void r600_init_query_functions(struct r600_context
* rctx
)
244 LIST_INITHEAD(&rctx
->query_list
);
246 rctx
->context
.create_query
= r600_create_query
;
247 rctx
->context
.destroy_query
= r600_destroy_query
;
248 rctx
->context
.begin_query
= r600_begin_query
;
249 rctx
->context
.end_query
= r600_end_query
;
250 rctx
->context
.get_query_result
= r600_get_query_result
;