Tizen 2.0 Release
[profile/ivi/osmesa.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(struct gl_context *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, max_idx;
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                 if (radeon->radeonScreen->chip_family >= CHIP_FAMILY_CEDAR)
60                         max_idx = 8 * 4; /* 8 DB's */
61                 else
62                         max_idx = 4 * 4; /* 4 DB's for r600, r700 */
63                 for (i = 0; i < max_idx; i += 4) {
64                         uint64_t start = (uint64_t)LE32_TO_CPU(result[i]) |
65                                          (uint64_t)LE32_TO_CPU(result[i + 1]) << 32;
66                         uint64_t end = (uint64_t)LE32_TO_CPU(result[i + 2]) |
67                                        (uint64_t)LE32_TO_CPU(result[i + 3]) << 32;
68                         if ((start & 0x8000000000000000) && (end & 0x8000000000000000)) {
69                                 uint64_t query_count = end - start;
70                                 query->Base.Result += query_count;
71
72                         }
73                         radeon_print(RADEON_STATE, RADEON_TRACE,
74                                      "%d start: %" PRIu64 ", end: %" PRIu64 " %" PRIu64 "\n", i, start, end, end - start);
75                 }
76         } else {
77                 for (i = 0; i < query->curr_offset/sizeof(uint32_t); ++i) {
78                         query->Base.Result += LE32_TO_CPU(result[i]);
79                         radeon_print(RADEON_STATE, RADEON_TRACE, "result[%d] = %d\n", i, LE32_TO_CPU(result[i]));
80                 }
81         }
82
83         radeon_bo_unmap(query->bo);
84 }
85
86 static struct gl_query_object * radeonNewQueryObject(struct gl_context *ctx, GLuint id)
87 {
88         struct radeon_query_object *query;
89
90         query = calloc(1, sizeof(struct radeon_query_object));
91
92         query->Base.Id = id;
93         query->Base.Result = 0;
94         query->Base.Active = GL_FALSE;
95         query->Base.Ready = GL_TRUE;
96
97         radeon_print(RADEON_STATE, RADEON_VERBOSE,"%s: query id %d\n", __FUNCTION__, query->Base.Id);
98
99         return &query->Base;
100 }
101
102 static void radeonDeleteQuery(struct gl_context *ctx, struct gl_query_object *q)
103 {
104         struct radeon_query_object *query = (struct radeon_query_object *)q;
105
106         radeon_print(RADEON_STATE, RADEON_NORMAL, "%s: query id %d\n", __FUNCTION__, q->Id);
107
108         if (query->bo) {
109                 radeon_bo_unref(query->bo);
110         }
111
112         free(query);
113 }
114
115 static void radeonWaitQuery(struct gl_context *ctx, struct gl_query_object *q)
116 {
117         radeonContextPtr radeon = RADEON_CONTEXT(ctx);
118         struct radeon_query_object *query = (struct radeon_query_object *)q;
119
120         /* If the cmdbuf with packets for this query hasn't been flushed yet, do it now */
121         if (radeon_bo_is_referenced_by_cs(query->bo, radeon->cmdbuf.cs))
122                 ctx->Driver.Flush(ctx);
123
124         radeon_print(RADEON_STATE, RADEON_VERBOSE, "%s: query id %d, bo %p, offset %d\n", __FUNCTION__, q->Id, query->bo, query->curr_offset);
125
126         radeonQueryGetResult(ctx, q);
127
128         query->Base.Ready = GL_TRUE;
129 }
130
131
132 static void radeonBeginQuery(struct gl_context *ctx, struct gl_query_object *q)
133 {
134         radeonContextPtr radeon = RADEON_CONTEXT(ctx);
135         struct radeon_query_object *query = (struct radeon_query_object *)q;
136
137         radeon_print(RADEON_STATE, RADEON_NORMAL, "%s: query id %d\n", __FUNCTION__, q->Id);
138
139         assert(radeon->query.current == NULL);
140
141         if (radeon->dma.flush)
142                 radeon->dma.flush(radeon->glCtx);
143
144         if (!query->bo) {
145                 query->bo = radeon_bo_open(radeon->radeonScreen->bom, 0, RADEON_QUERY_PAGE_SIZE, RADEON_QUERY_PAGE_SIZE, RADEON_GEM_DOMAIN_GTT, 0);
146         }
147         query->curr_offset = 0;
148
149         radeon->query.current = query;
150
151         radeon->query.queryobj.dirty = GL_TRUE;
152         radeon->hw.is_dirty = GL_TRUE;
153 }
154
155 void radeonEmitQueryEnd(struct gl_context *ctx)
156 {
157         radeonContextPtr radeon = RADEON_CONTEXT(ctx);
158         struct radeon_query_object *query = radeon->query.current;
159
160         if (!query)
161                 return;
162
163         if (query->emitted_begin == GL_FALSE)
164                 return;
165
166         radeon_print(RADEON_STATE, RADEON_NORMAL, "%s: query id %d, bo %p, offset %d\n", __FUNCTION__, query->Base.Id, query->bo, query->curr_offset);
167
168         radeon_cs_space_check_with_bo(radeon->cmdbuf.cs,
169                                       query->bo,
170                                       0, RADEON_GEM_DOMAIN_GTT);
171
172         radeon->vtbl.emit_query_finish(radeon);
173 }
174
175 static void radeonEndQuery(struct gl_context *ctx, struct gl_query_object *q)
176 {
177         radeonContextPtr radeon = RADEON_CONTEXT(ctx);
178
179         radeon_print(RADEON_STATE, RADEON_NORMAL, "%s: query id %d\n", __FUNCTION__, q->Id);
180
181         if (radeon->dma.flush)
182                 radeon->dma.flush(radeon->glCtx);
183         radeonEmitQueryEnd(ctx);
184
185         radeon->query.current = NULL;
186 }
187
188 static void radeonCheckQuery(struct gl_context *ctx, struct gl_query_object *q)
189 {
190         radeon_print(RADEON_STATE, RADEON_TRACE, "%s: query id %d\n", __FUNCTION__, q->Id);
191
192 #ifdef DRM_RADEON_GEM_BUSY
193         radeonContextPtr radeon = RADEON_CONTEXT(ctx);
194
195         if (radeon->radeonScreen->kernel_mm) {
196                 struct radeon_query_object *query = (struct radeon_query_object *)q;
197                 uint32_t domain;
198
199                 /* Need to perform a flush, as per ARB_occlusion_query spec */
200                 if (radeon_bo_is_referenced_by_cs(query->bo, radeon->cmdbuf.cs)) {
201                         ctx->Driver.Flush(ctx);
202                 }
203
204                 if (radeon_bo_is_busy(query->bo, &domain) == 0) {
205                         radeonQueryGetResult(ctx, q);
206                         query->Base.Ready = GL_TRUE;
207                 }
208         } else {
209                 radeonWaitQuery(ctx, q);
210         }
211 #else
212         radeonWaitQuery(ctx, q);
213 #endif
214 }
215
216 void radeonInitQueryObjFunctions(struct dd_function_table *functions)
217 {
218         functions->NewQueryObject = radeonNewQueryObject;
219         functions->DeleteQuery = radeonDeleteQuery;
220         functions->BeginQuery = radeonBeginQuery;
221         functions->EndQuery = radeonEndQuery;
222         functions->CheckQuery = radeonCheckQuery;
223         functions->WaitQuery = radeonWaitQuery;
224 }
225
226 int radeon_check_query_active(struct gl_context *ctx, struct radeon_state_atom *atom)
227 {
228         radeonContextPtr radeon = RADEON_CONTEXT(ctx);
229         struct radeon_query_object *query = radeon->query.current;
230
231         if (!query || query->emitted_begin)
232                 return 0;
233         return atom->cmd_size;
234 }
235
236 void radeon_emit_queryobj(struct gl_context *ctx, struct radeon_state_atom *atom)
237 {
238         radeonContextPtr radeon = RADEON_CONTEXT(ctx);
239         BATCH_LOCALS(radeon);
240         int dwords;
241
242         dwords = (*atom->check) (ctx, atom);
243
244         BEGIN_BATCH_NO_AUTOSTATE(dwords);
245         OUT_BATCH_TABLE(atom->cmd, dwords);
246         END_BATCH();
247
248         radeon->query.current->emitted_begin = GL_TRUE;
249 }