1 /*
2 * Copyright 2012 Red Hat Inc.
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 shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Ben Skeggs
23 *
24 */
25
26 #include "nv_object.xml.h"
27 #include "nv30/nv30-40_3d.xml.h"
28 #include "nv30/nv30_screen.h"
29 #include "nv30/nv30_context.h"
30
31 struct nv30_query_object {
32 struct list_head list;
33 struct nouveau_heap *hw;
34 };
35
36 static volatile void *
nv30_ntfy(struct nv30_screen * screen,struct nv30_query_object * qo)37 nv30_ntfy(struct nv30_screen *screen, struct nv30_query_object *qo)
38 {
39 struct nv04_notify *query = screen->query->data;
40 struct nouveau_bo *notify = screen->notify;
41 volatile void *ntfy = NULL;
42
43 if (qo && qo->hw)
44 ntfy = (char *)notify->map + query->offset + qo->hw->start;
45
46 return ntfy;
47 }
48
49 static void
nv30_query_object_del(struct nv30_screen * screen,struct nv30_query_object ** po)50 nv30_query_object_del(struct nv30_screen *screen, struct nv30_query_object **po)
51 {
52 struct nv30_query_object *qo = *po; *po = NULL;
53 if (qo) {
54 volatile uint32_t *ntfy = nv30_ntfy(screen, qo);
55 while (ntfy[3] & 0xff000000) {
56 }
57 nouveau_heap_free(&qo->hw);
58 list_del(&qo->list);
59 FREE(qo);
60 }
61 }
62
63 static struct nv30_query_object *
nv30_query_object_new(struct nv30_screen * screen)64 nv30_query_object_new(struct nv30_screen *screen)
65 {
66 struct nv30_query_object *oq, *qo = CALLOC_STRUCT(nv30_query_object);
67 volatile uint32_t *ntfy;
68
69 if (!qo)
70 return NULL;
71
72 /* allocate a new hw query object, if no hw objects left we need to
73 * spin waiting for one to become free
74 */
75 while (nouveau_heap_alloc(screen->query_heap, 32, NULL, &qo->hw)) {
76 oq = list_first_entry(&screen->queries, struct nv30_query_object, list);
77 nv30_query_object_del(screen, &oq);
78 }
79
80 list_addtail(&qo->list, &screen->queries);
81
82 ntfy = nv30_ntfy(screen, qo);
83 ntfy[0] = 0x00000000;
84 ntfy[1] = 0x00000000;
85 ntfy[2] = 0x00000000;
86 ntfy[3] = 0x01000000;
87 return qo;
88 }
89
90 struct nv30_query {
91 struct nv30_query_object *qo[2];
92 unsigned type;
93 uint32_t report;
94 uint32_t enable;
95 uint64_t result;
96 };
97
98 static inline struct nv30_query *
nv30_query(struct pipe_query * pipe)99 nv30_query(struct pipe_query *pipe)
100 {
101 return (struct nv30_query *)pipe;
102 }
103
104 static struct pipe_query *
nv30_query_create(struct pipe_context * pipe,unsigned type,unsigned index)105 nv30_query_create(struct pipe_context *pipe, unsigned type, unsigned index)
106 {
107 struct nv30_query *q = CALLOC_STRUCT(nv30_query);
108 if (!q)
109 return NULL;
110
111 q->type = type;
112
113 switch (q->type) {
114 case PIPE_QUERY_TIMESTAMP:
115 case PIPE_QUERY_TIME_ELAPSED:
116 q->enable = 0x0000;
117 q->report = 1;
118 break;
119 case PIPE_QUERY_OCCLUSION_COUNTER:
120 case PIPE_QUERY_OCCLUSION_PREDICATE:
121 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
122 q->enable = NV30_3D_QUERY_ENABLE;
123 q->report = 1;
124 break;
125 case NV30_QUERY_ZCULL_0:
126 case NV30_QUERY_ZCULL_1:
127 case NV30_QUERY_ZCULL_2:
128 case NV30_QUERY_ZCULL_3:
129 q->enable = 0x1804;
130 q->report = 2 + (q->type - NV30_QUERY_ZCULL_0);
131 break;
132 default:
133 FREE(q);
134 return NULL;
135 }
136
137 return (struct pipe_query *)q;
138 }
139
140 static void
nv30_query_destroy(struct pipe_context * pipe,struct pipe_query * pq)141 nv30_query_destroy(struct pipe_context *pipe, struct pipe_query *pq)
142 {
143 FREE(pq);
144 }
145
146 static bool
nv30_query_begin(struct pipe_context * pipe,struct pipe_query * pq)147 nv30_query_begin(struct pipe_context *pipe, struct pipe_query *pq)
148 {
149 struct nv30_context *nv30 = nv30_context(pipe);
150 struct nv30_query *q = nv30_query(pq);
151 struct nouveau_pushbuf *push = nv30->base.pushbuf;
152
153 switch (q->type) {
154 case PIPE_QUERY_TIME_ELAPSED:
155 q->qo[0] = nv30_query_object_new(nv30->screen);
156 if (q->qo[0]) {
157 BEGIN_NV04(push, NV30_3D(QUERY_GET), 1);
158 PUSH_DATA (push, (q->report << 24) | q->qo[0]->hw->start);
159 }
160 break;
161 case PIPE_QUERY_TIMESTAMP:
162 return true;
163 default:
164 BEGIN_NV04(push, NV30_3D(QUERY_RESET), 1);
165 PUSH_DATA (push, q->report);
166 break;
167 }
168
169 if (q->enable) {
170 BEGIN_NV04(push, SUBC_3D(q->enable), 1);
171 PUSH_DATA (push, 1);
172 }
173 return true;
174 }
175
176 static bool
nv30_query_end(struct pipe_context * pipe,struct pipe_query * pq)177 nv30_query_end(struct pipe_context *pipe, struct pipe_query *pq)
178 {
179 struct nv30_context *nv30 = nv30_context(pipe);
180 struct nv30_screen *screen = nv30->screen;
181 struct nv30_query *q = nv30_query(pq);
182 struct nouveau_pushbuf *push = nv30->base.pushbuf;
183
184 q->qo[1] = nv30_query_object_new(screen);
185 if (q->qo[1]) {
186 BEGIN_NV04(push, NV30_3D(QUERY_GET), 1);
187 PUSH_DATA (push, (q->report << 24) | q->qo[1]->hw->start);
188 }
189
190 if (q->enable) {
191 BEGIN_NV04(push, SUBC_3D(q->enable), 1);
192 PUSH_DATA (push, 0);
193 }
194 PUSH_KICK (push);
195 return true;
196 }
197
198 static bool
nv30_query_result(struct pipe_context * pipe,struct pipe_query * pq,bool wait,union pipe_query_result * result)199 nv30_query_result(struct pipe_context *pipe, struct pipe_query *pq,
200 bool wait, union pipe_query_result *result)
201 {
202 struct nv30_screen *screen = nv30_screen(pipe->screen);
203 struct nv30_query *q = nv30_query(pq);
204 volatile uint32_t *ntfy0 = nv30_ntfy(screen, q->qo[0]);
205 volatile uint32_t *ntfy1 = nv30_ntfy(screen, q->qo[1]);
206
207 if (ntfy1) {
208 while (ntfy1[3] & 0xff000000) {
209 if (!wait)
210 return false;
211 }
212
213 switch (q->type) {
214 case PIPE_QUERY_TIMESTAMP:
215 q->result = *(uint64_t *)&ntfy1[0];
216 break;
217 case PIPE_QUERY_TIME_ELAPSED:
218 q->result = *(uint64_t *)&ntfy1[0] - *(uint64_t *)&ntfy0[0];
219 break;
220 default:
221 q->result = ntfy1[2];
222 break;
223 }
224
225 nv30_query_object_del(screen, &q->qo[0]);
226 nv30_query_object_del(screen, &q->qo[1]);
227 }
228
229 if (q->type == PIPE_QUERY_OCCLUSION_PREDICATE ||
230 q->type == PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE)
231 result->b = !!q->result;
232 else
233 result->u64 = q->result;
234 return true;
235 }
236
237 static void
nv40_query_render_condition(struct pipe_context * pipe,struct pipe_query * pq,bool condition,enum pipe_render_cond_flag mode)238 nv40_query_render_condition(struct pipe_context *pipe,
239 struct pipe_query *pq,
240 bool condition, enum pipe_render_cond_flag mode)
241 {
242 struct nv30_context *nv30 = nv30_context(pipe);
243 struct nv30_query *q = nv30_query(pq);
244 struct nouveau_pushbuf *push = nv30->base.pushbuf;
245
246 nv30->render_cond_query = pq;
247 nv30->render_cond_mode = mode;
248 nv30->render_cond_cond = condition;
249
250 if (!pq) {
251 BEGIN_NV04(push, SUBC_3D(0x1e98), 1);
252 PUSH_DATA (push, 0x01000000);
253 return;
254 }
255
256 if (mode == PIPE_RENDER_COND_WAIT ||
257 mode == PIPE_RENDER_COND_BY_REGION_WAIT) {
258 BEGIN_NV04(push, SUBC_3D(0x0110), 1);
259 PUSH_DATA (push, 0);
260 }
261
262 BEGIN_NV04(push, SUBC_3D(0x1e98), 1);
263 PUSH_DATA (push, 0x02000000 | q->qo[1]->hw->start);
264 }
265
266 static void
nv30_set_active_query_state(struct pipe_context * pipe,bool enable)267 nv30_set_active_query_state(struct pipe_context *pipe, bool enable)
268 {
269 }
270
271 void
nv30_query_init(struct pipe_context * pipe)272 nv30_query_init(struct pipe_context *pipe)
273 {
274 struct nouveau_object *eng3d = nv30_context(pipe)->screen->eng3d;
275
276 pipe->create_query = nv30_query_create;
277 pipe->destroy_query = nv30_query_destroy;
278 pipe->begin_query = nv30_query_begin;
279 pipe->end_query = nv30_query_end;
280 pipe->get_query_result = nv30_query_result;
281 pipe->set_active_query_state = nv30_set_active_query_state;
282 if (eng3d->oclass >= NV40_3D_CLASS)
283 pipe->render_condition = nv40_query_render_condition;
284 }
285