Merge remote branch 'origin/master' into nv50-compiler
[mesa.git] / src / mesa / drivers / dri / radeon / radeon_queryobj.c
1 /*
2 * Copyright © 2008-2009 Maciej Cencora <m.cencora@gmail.com>
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 * 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:
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 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
21 * IN THE SOFTWARE.
22 *
23 * Authors:
24 * Maciej Cencora <m.cencora@gmail.com>
25 *
26 */
27 #include "radeon_common.h"
28 #include "radeon_queryobj.h"
29 #include "radeon_debug.h"
30
31 #include "main/imports.h"
32 #include "main/simple_list.h"
33
34 #include <inttypes.h>
35
36 static void radeonQueryGetResult(GLcontext *ctx, struct gl_query_object *q)
37 {
38 radeonContextPtr radeon = RADEON_CONTEXT(ctx);
39 struct radeon_query_object *query = (struct radeon_query_object *)q;
40 uint32_t *result;
41 int i;
42
43 radeon_print(RADEON_STATE, RADEON_VERBOSE,
44 "%s: query id %d, result %d\n",
45 __FUNCTION__, query->Base.Id, (int) query->Base.Result);
46
47 radeon_bo_map(query->bo, GL_FALSE);
48 result = query->bo->ptr;
49
50 query->Base.Result = 0;
51 if (IS_R600_CLASS(radeon->radeonScreen)) {
52 /* ZPASS EVENT writes alternating qwords
53 * At query start we set the start offset to 0 and
54 * hw writes zpass start counts to qwords 0, 2, 4, 6.
55 * At query end we set the start offset to 8 and
56 * hw writes zpass end counts to qwords 1, 3, 5, 7.
57 * then we substract. MSB is the valid bit.
58 */
59 for (i = 0; i < 16; i += 4) {
60 uint64_t start = (uint64_t)LE32_TO_CPU(result[i]) |
61 (uint64_t)LE32_TO_CPU(result[i + 1]) << 32;
62 uint64_t end = (uint64_t)LE32_TO_CPU(result[i + 2]) |
63 (uint64_t)LE32_TO_CPU(result[i + 3]) << 32;
64 if ((start & 0x8000000000000000) && (end & 0x8000000000000000)) {
65 uint64_t query_count = end - start;
66 query->Base.Result += query_count;
67
68 }
69 radeon_print(RADEON_STATE, RADEON_TRACE,
70 "%d start: %" PRIu64 ", end: %" PRIu64 " %" PRIu64 "\n", i, start, end, end - start);
71 }
72 } else {
73 for (i = 0; i < query->curr_offset/sizeof(uint32_t); ++i) {
74 query->Base.Result += LE32_TO_CPU(result[i]);
75 radeon_print(RADEON_STATE, RADEON_TRACE, "result[%d] = %d\n", i, LE32_TO_CPU(result[i]));
76 }
77 }
78
79 radeon_bo_unmap(query->bo);
80 }
81
82 static struct gl_query_object * radeonNewQueryObject(GLcontext *ctx, GLuint id)
83 {
84 struct radeon_query_object *query;
85
86 query = calloc(1, sizeof(struct radeon_query_object));
87
88 query->Base.Id = id;
89 query->Base.Result = 0;
90 query->Base.Active = GL_FALSE;
91 query->Base.Ready = GL_TRUE;
92
93 radeon_print(RADEON_STATE, RADEON_VERBOSE,"%s: query id %d\n", __FUNCTION__, query->Base.Id);
94
95 return &query->Base;
96 }
97
98 static void radeonDeleteQuery(GLcontext *ctx, struct gl_query_object *q)
99 {
100 struct radeon_query_object *query = (struct radeon_query_object *)q;
101
102 radeon_print(RADEON_STATE, RADEON_NORMAL, "%s: query id %d\n", __FUNCTION__, q->Id);
103
104 if (query->bo) {
105 radeon_bo_unref(query->bo);
106 }
107
108 free(query);
109 }
110
111 static void radeonWaitQuery(GLcontext *ctx, struct gl_query_object *q)
112 {
113 radeonContextPtr radeon = RADEON_CONTEXT(ctx);
114 struct radeon_query_object *query = (struct radeon_query_object *)q;
115
116 /* If the cmdbuf with packets for this query hasn't been flushed yet, do it now */
117 if (radeon_bo_is_referenced_by_cs(query->bo, radeon->cmdbuf.cs))
118 ctx->Driver.Flush(ctx);
119
120 radeon_print(RADEON_STATE, RADEON_VERBOSE, "%s: query id %d, bo %p, offset %d\n", __FUNCTION__, q->Id, query->bo, query->curr_offset);
121
122 radeonQueryGetResult(ctx, q);
123
124 query->Base.Ready = GL_TRUE;
125 }
126
127
128 static void radeonBeginQuery(GLcontext *ctx, struct gl_query_object *q)
129 {
130 radeonContextPtr radeon = RADEON_CONTEXT(ctx);
131 struct radeon_query_object *query = (struct radeon_query_object *)q;
132
133 radeon_print(RADEON_STATE, RADEON_NORMAL, "%s: query id %d\n", __FUNCTION__, q->Id);
134
135 assert(radeon->query.current == NULL);
136
137 if (radeon->dma.flush)
138 radeon->dma.flush(radeon->glCtx);
139
140 if (!query->bo) {
141 query->bo = radeon_bo_open(radeon->radeonScreen->bom, 0, RADEON_QUERY_PAGE_SIZE, RADEON_QUERY_PAGE_SIZE, RADEON_GEM_DOMAIN_GTT, 0);
142 }
143 query->curr_offset = 0;
144
145 radeon->query.current = query;
146
147 radeon->query.queryobj.dirty = GL_TRUE;
148 radeon->hw.is_dirty = GL_TRUE;
149 }
150
151 void radeonEmitQueryEnd(GLcontext *ctx)
152 {
153 radeonContextPtr radeon = RADEON_CONTEXT(ctx);
154 struct radeon_query_object *query = radeon->query.current;
155
156 if (!query)
157 return;
158
159 if (query->emitted_begin == GL_FALSE)
160 return;
161
162 radeon_print(RADEON_STATE, RADEON_NORMAL, "%s: query id %d, bo %p, offset %d\n", __FUNCTION__, query->Base.Id, query->bo, query->curr_offset);
163
164 radeon_cs_space_check_with_bo(radeon->cmdbuf.cs,
165 query->bo,
166 0, RADEON_GEM_DOMAIN_GTT);
167
168 radeon->vtbl.emit_query_finish(radeon);
169 }
170
171 static void radeonEndQuery(GLcontext *ctx, struct gl_query_object *q)
172 {
173 radeonContextPtr radeon = RADEON_CONTEXT(ctx);
174
175 radeon_print(RADEON_STATE, RADEON_NORMAL, "%s: query id %d\n", __FUNCTION__, q->Id);
176
177 if (radeon->dma.flush)
178 radeon->dma.flush(radeon->glCtx);
179 radeonEmitQueryEnd(ctx);
180
181 radeon->query.current = NULL;
182 }
183
184 static void radeonCheckQuery(GLcontext *ctx, struct gl_query_object *q)
185 {
186 radeon_print(RADEON_STATE, RADEON_TRACE, "%s: query id %d\n", __FUNCTION__, q->Id);
187
188 #ifdef DRM_RADEON_GEM_BUSY
189 radeonContextPtr radeon = RADEON_CONTEXT(ctx);
190
191 if (radeon->radeonScreen->kernel_mm) {
192 struct radeon_query_object *query = (struct radeon_query_object *)q;
193 uint32_t domain;
194
195 /* Need to perform a flush, as per ARB_occlusion_query spec */
196 if (radeon_bo_is_referenced_by_cs(query->bo, radeon->cmdbuf.cs)) {
197 ctx->Driver.Flush(ctx);
198 }
199
200 if (radeon_bo_is_busy(query->bo, &domain) == 0) {
201 radeonQueryGetResult(ctx, q);
202 query->Base.Ready = GL_TRUE;
203 }
204 } else {
205 radeonWaitQuery(ctx, q);
206 }
207 #else
208 radeonWaitQuery(ctx, q);
209 #endif
210 }
211
212 void radeonInitQueryObjFunctions(struct dd_function_table *functions)
213 {
214 functions->NewQueryObject = radeonNewQueryObject;
215 functions->DeleteQuery = radeonDeleteQuery;
216 functions->BeginQuery = radeonBeginQuery;
217 functions->EndQuery = radeonEndQuery;
218 functions->CheckQuery = radeonCheckQuery;
219 functions->WaitQuery = radeonWaitQuery;
220 }
221
222 int radeon_check_query_active(GLcontext *ctx, struct radeon_state_atom *atom)
223 {
224 radeonContextPtr radeon = RADEON_CONTEXT(ctx);
225 struct radeon_query_object *query = radeon->query.current;
226
227 if (!query || query->emitted_begin)
228 return 0;
229 return atom->cmd_size;
230 }
231
232 void radeon_emit_queryobj(GLcontext *ctx, struct radeon_state_atom *atom)
233 {
234 radeonContextPtr radeon = RADEON_CONTEXT(ctx);
235 BATCH_LOCALS(radeon);
236 int dwords;
237
238 dwords = (*atom->check) (ctx, atom);
239
240 BEGIN_BATCH_NO_AUTOSTATE(dwords);
241 OUT_BATCH_TABLE(atom->cmd, dwords);
242 END_BATCH();
243
244 radeon->query.current->emitted_begin = GL_TRUE;
245 }