2 * Copyright © 2008-2009 Maciej Cencora <m.cencora@gmail.com>
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 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * 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 NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 * Maciej Cencora <m.cencora@gmail.com>
27 #include "radeon_common.h"
28 #include "radeon_queryobj.h"
29 #include "radeon_debug.h"
31 #include "main/imports.h"
32 #include "main/simple_list.h"
34 static int radeonQueryIsFlushed(GLcontext
*ctx
, struct gl_query_object
*q
)
36 radeonContextPtr radeon
= RADEON_CONTEXT(ctx
);
37 struct radeon_query_object
*tmp
, *query
= (struct radeon_query_object
*)q
;
39 foreach(tmp
, &radeon
->query
.not_flushed_head
) {
48 static void radeonQueryGetResult(GLcontext
*ctx
, struct gl_query_object
*q
)
50 radeonContextPtr radeon
= RADEON_CONTEXT(ctx
);
51 struct radeon_query_object
*query
= (struct radeon_query_object
*)q
;
55 radeon_print(RADEON_STATE
, RADEON_VERBOSE
,
56 "%s: query id %d, result %d\n",
57 __FUNCTION__
, query
->Base
.Id
, (int) query
->Base
.Result
);
59 radeon_bo_map(query
->bo
, GL_FALSE
);
60 result
= query
->bo
->ptr
;
62 query
->Base
.Result
= 0;
63 if (IS_R600_CLASS(radeon
->radeonScreen
)) {
64 /* ZPASS EVENT writes alternating qwords
65 * At query start we set the start offset to 0 and
66 * hw writes zpass start counts to qwords 0, 2, 4, 6.
67 * At query end we set the start offset to 8 and
68 * hw writes zpass end counts to qwords 1, 3, 5, 7.
69 * then we substract. MSB is the valid bit.
71 for (i
= 0; i
< 16; i
+= 4) {
72 uint64_t start
= (uint64_t)LE32_TO_CPU(result
[i
]) |
73 (uint64_t)LE32_TO_CPU(result
[i
+ 1]) << 32;
74 uint64_t end
= (uint64_t)LE32_TO_CPU(result
[i
+ 2]) |
75 (uint64_t)LE32_TO_CPU(result
[i
+ 3]) << 32;
76 if ((start
& 0x8000000000000000) && (end
& 0x8000000000000000)) {
77 uint64_t query_count
= end
- start
;
78 query
->Base
.Result
+= query_count
;
81 radeon_print(RADEON_STATE
, RADEON_TRACE
,
82 "%d start: %lx, end: %lx %ld\n", i
, start
, end
, end
- start
);
85 for (i
= 0; i
< query
->curr_offset
/sizeof(uint32_t); ++i
) {
86 query
->Base
.Result
+= LE32_TO_CPU(result
[i
]);
87 radeon_print(RADEON_STATE
, RADEON_TRACE
, "result[%d] = %d\n", i
, LE32_TO_CPU(result
[i
]));
91 radeon_bo_unmap(query
->bo
);
94 static struct gl_query_object
* radeonNewQueryObject(GLcontext
*ctx
, GLuint id
)
96 struct radeon_query_object
*query
;
98 query
= _mesa_calloc(sizeof(struct radeon_query_object
));
101 query
->Base
.Result
= 0;
102 query
->Base
.Active
= GL_FALSE
;
103 query
->Base
.Ready
= GL_TRUE
;
105 radeon_print(RADEON_STATE
, RADEON_VERBOSE
,"%s: query id %d\n", __FUNCTION__
, query
->Base
.Id
);
110 static void radeonDeleteQuery(GLcontext
*ctx
, struct gl_query_object
*q
)
112 struct radeon_query_object
*query
= (struct radeon_query_object
*)q
;
114 radeon_print(RADEON_STATE
, RADEON_NORMAL
, "%s: query id %d\n", __FUNCTION__
, q
->Id
);
117 radeon_bo_unref(query
->bo
);
123 static void radeonWaitQuery(GLcontext
*ctx
, struct gl_query_object
*q
)
125 struct radeon_query_object
*query
= (struct radeon_query_object
*)q
;
127 /* If the cmdbuf with packets for this query hasn't been flushed yet, do it now */
128 if (!radeonQueryIsFlushed(ctx
, q
))
129 ctx
->Driver
.Flush(ctx
);
131 radeon_print(RADEON_STATE
, RADEON_VERBOSE
, "%s: query id %d, bo %p, offset %d\n", __FUNCTION__
, q
->Id
, query
->bo
, query
->curr_offset
);
133 radeonQueryGetResult(ctx
, q
);
135 query
->Base
.Ready
= GL_TRUE
;
139 static void radeonBeginQuery(GLcontext
*ctx
, struct gl_query_object
*q
)
141 radeonContextPtr radeon
= RADEON_CONTEXT(ctx
);
142 struct radeon_query_object
*query
= (struct radeon_query_object
*)q
;
144 radeon_print(RADEON_STATE
, RADEON_NORMAL
, "%s: query id %d\n", __FUNCTION__
, q
->Id
);
146 assert(radeon
->query
.current
== NULL
);
148 if (radeon
->dma
.flush
)
149 radeon
->dma
.flush(radeon
->glCtx
);
152 query
->bo
= radeon_bo_open(radeon
->radeonScreen
->bom
, 0, RADEON_QUERY_PAGE_SIZE
, RADEON_QUERY_PAGE_SIZE
, RADEON_GEM_DOMAIN_GTT
, 0);
154 query
->curr_offset
= 0;
156 radeon
->query
.current
= query
;
158 radeon
->query
.queryobj
.dirty
= GL_TRUE
;
159 radeon
->hw
.is_dirty
= GL_TRUE
;
160 insert_at_tail(&radeon
->query
.not_flushed_head
, query
);
164 void radeonEmitQueryEnd(GLcontext
*ctx
)
166 radeonContextPtr radeon
= RADEON_CONTEXT(ctx
);
167 struct radeon_query_object
*query
= radeon
->query
.current
;
172 if (query
->emitted_begin
== GL_FALSE
)
175 radeon_print(RADEON_STATE
, RADEON_NORMAL
, "%s: query id %d, bo %p, offset %d\n", __FUNCTION__
, query
->Base
.Id
, query
->bo
, query
->curr_offset
);
177 radeon_cs_space_check_with_bo(radeon
->cmdbuf
.cs
,
179 0, RADEON_GEM_DOMAIN_GTT
);
181 radeon
->vtbl
.emit_query_finish(radeon
);
184 static void radeonEndQuery(GLcontext
*ctx
, struct gl_query_object
*q
)
186 radeonContextPtr radeon
= RADEON_CONTEXT(ctx
);
188 radeon_print(RADEON_STATE
, RADEON_NORMAL
, "%s: query id %d\n", __FUNCTION__
, q
->Id
);
190 if (radeon
->dma
.flush
)
191 radeon
->dma
.flush(radeon
->glCtx
);
192 radeonEmitQueryEnd(ctx
);
194 radeon
->query
.current
= NULL
;
197 static void radeonCheckQuery(GLcontext
*ctx
, struct gl_query_object
*q
)
199 radeon_print(RADEON_STATE
, RADEON_TRACE
, "%s: query id %d\n", __FUNCTION__
, q
->Id
);
201 #ifdef DRM_RADEON_GEM_BUSY
202 radeonContextPtr radeon
= RADEON_CONTEXT(ctx
);
204 if (radeon
->radeonScreen
->kernel_mm
) {
205 struct radeon_query_object
*query
= (struct radeon_query_object
*)q
;
208 /* Need to perform a flush, as per ARB_occlusion_query spec */
209 if (!radeonQueryIsFlushed(ctx
, q
)) {
210 ctx
->Driver
.Flush(ctx
);
213 if (radeon_bo_is_busy(query
->bo
, &domain
) == 0) {
214 radeonQueryGetResult(ctx
, q
);
215 query
->Base
.Ready
= GL_TRUE
;
218 radeonWaitQuery(ctx
, q
);
221 radeonWaitQuery(ctx
, q
);
225 void radeonInitQueryObjFunctions(struct dd_function_table
*functions
)
227 functions
->NewQueryObject
= radeonNewQueryObject
;
228 functions
->DeleteQuery
= radeonDeleteQuery
;
229 functions
->BeginQuery
= radeonBeginQuery
;
230 functions
->EndQuery
= radeonEndQuery
;
231 functions
->CheckQuery
= radeonCheckQuery
;
232 functions
->WaitQuery
= radeonWaitQuery
;
235 int radeon_check_query_active(GLcontext
*ctx
, struct radeon_state_atom
*atom
)
237 radeonContextPtr radeon
= RADEON_CONTEXT(ctx
);
238 struct radeon_query_object
*query
= radeon
->query
.current
;
240 if (!query
|| query
->emitted_begin
)
242 return atom
->cmd_size
;
245 void radeon_emit_queryobj(GLcontext
*ctx
, struct radeon_state_atom
*atom
)
247 radeonContextPtr radeon
= RADEON_CONTEXT(ctx
);
248 BATCH_LOCALS(radeon
);
251 dwords
= (*atom
->check
) (ctx
, atom
);
253 BEGIN_BATCH_NO_AUTOSTATE(dwords
);
254 OUT_BATCH_TABLE(atom
->cmd
, dwords
);
257 radeon
->query
.current
->emitted_begin
= GL_TRUE
;