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 #define LIST_FIRST_ENTRY(__type, __item, __field) \
32 LIST_ENTRY(__type, (__item)->next, __field)
33
34 struct nv30_query_object {
35 struct list_head list;
36 struct nouveau_heap *hw;
37 };
38
39 static volatile void *
nv30_ntfy(struct nv30_screen * screen,struct nv30_query_object * qo)40 nv30_ntfy(struct nv30_screen *screen, struct nv30_query_object *qo)
41 {
42 struct nv04_notify *query = screen->query->data;
43 struct nouveau_bo *notify = screen->notify;
44 volatile void *ntfy = NULL;
45
46 if (qo && qo->hw)
47 ntfy = (char *)notify->map + query->offset + qo->hw->start;
48
49 return ntfy;
50 }
51
52 static void
nv30_query_object_del(struct nv30_screen * screen,struct nv30_query_object ** po)53 nv30_query_object_del(struct nv30_screen *screen, struct nv30_query_object **po)
54 {
55 struct nv30_query_object *qo = *po; *po = NULL;
56 if (qo) {
57 volatile uint32_t *ntfy = nv30_ntfy(screen, qo);
58 while (ntfy[3] & 0xff000000) {
59 }
60 nouveau_heap_free(&qo->hw);
61 LIST_DEL(&qo->list);
62 FREE(qo);
63 }
64 }
65
66 static struct nv30_query_object *
nv30_query_object_new(struct nv30_screen * screen)67 nv30_query_object_new(struct nv30_screen *screen)
68 {
69 struct nv30_query_object *oq, *qo = CALLOC_STRUCT(nv30_query_object);
70 volatile uint32_t *ntfy;
71
72 if (!qo)
73 return NULL;
74
75 /* allocate a new hw query object, if no hw objects left we need to
76 * spin waiting for one to become free
77 */
78 while (nouveau_heap_alloc(screen->query_heap, 32, NULL, &qo->hw)) {
79 oq = LIST_FIRST_ENTRY(struct nv30_query_object, &screen->queries, list);
80 nv30_query_object_del(screen, &oq);
81 }
82
83 LIST_ADDTAIL(&qo->list, &screen->queries);
84
85 ntfy = nv30_ntfy(screen, qo);
86 ntfy[0] = 0x00000000;
87 ntfy[1] = 0x00000000;
88 ntfy[2] = 0x00000000;
89 ntfy[3] = 0x01000000;
90 return qo;
91 }
92
93 struct nv30_query {
94 struct nv30_query_object *qo[2];
95 unsigned type;
96 uint32_t report;
97 uint32_t enable;
98 uint64_t result;
99 };
100
101 static inline struct nv30_query *
nv30_query(struct pipe_query * pipe)102 nv30_query(struct pipe_query *pipe)
103 {
104 return (struct nv30_query *)pipe;
105 }
106
107 static struct pipe_query *
nv30_query_create(struct pipe_context * pipe,unsigned type,unsigned index)108 nv30_query_create(struct pipe_context *pipe, unsigned type, unsigned index)
109 {
110 struct nv30_query *q = CALLOC_STRUCT(nv30_query);
111 if (!q)
112 return NULL;
113
114 q->type = type;
115
116 switch (q->type) {
117 case PIPE_QUERY_TIMESTAMP:
118 case PIPE_QUERY_TIME_ELAPSED:
119 q->enable = 0x0000;
120 q->report = 1;
121 break;
122 case PIPE_QUERY_OCCLUSION_COUNTER:
123 case PIPE_QUERY_OCCLUSION_PREDICATE:
124 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
125 q->enable = NV30_3D_QUERY_ENABLE;
126 q->report = 1;
127 break;
128 case NV30_QUERY_ZCULL_0:
129 case NV30_QUERY_ZCULL_1:
130 case NV30_QUERY_ZCULL_2:
131 case NV30_QUERY_ZCULL_3:
132 q->enable = 0x1804;
133 q->report = 2 + (q->type - NV30_QUERY_ZCULL_0);
134 break;
135 default:
136 FREE(q);
137 return NULL;
138 }
139
140 return (struct pipe_query *)q;
141 }
142
143 static void
nv30_query_destroy(struct pipe_context * pipe,struct pipe_query * pq)144 nv30_query_destroy(struct pipe_context *pipe, struct pipe_query *pq)
145 {
146 FREE(pq);
147 }
148
149 static boolean
nv30_query_begin(struct pipe_context * pipe,struct pipe_query * pq)150 nv30_query_begin(struct pipe_context *pipe, struct pipe_query *pq)
151 {
152 struct nv30_context *nv30 = nv30_context(pipe);
153 struct nv30_query *q = nv30_query(pq);
154 struct nouveau_pushbuf *push = nv30->base.pushbuf;
155
156 switch (q->type) {
157 case PIPE_QUERY_TIME_ELAPSED:
158 q->qo[0] = nv30_query_object_new(nv30->screen);
159 if (q->qo[0]) {
160 BEGIN_NV04(push, NV30_3D(QUERY_GET), 1);
161 PUSH_DATA (push, (q->report << 24) | q->qo[0]->hw->start);
162 }
163 break;
164 case PIPE_QUERY_TIMESTAMP:
165 return true;
166 default:
167 BEGIN_NV04(push, NV30_3D(QUERY_RESET), 1);
168 PUSH_DATA (push, q->report);
169 break;
170 }
171
172 if (q->enable) {
173 BEGIN_NV04(push, SUBC_3D(q->enable), 1);
174 PUSH_DATA (push, 1);
175 }
176 return true;
177 }
178
179 static bool
nv30_query_end(struct pipe_context * pipe,struct pipe_query * pq)180 nv30_query_end(struct pipe_context *pipe, struct pipe_query *pq)
181 {
182 struct nv30_context *nv30 = nv30_context(pipe);
183 struct nv30_screen *screen = nv30->screen;
184 struct nv30_query *q = nv30_query(pq);
185 struct nouveau_pushbuf *push = nv30->base.pushbuf;
186
187 q->qo[1] = nv30_query_object_new(screen);
188 if (q->qo[1]) {
189 BEGIN_NV04(push, NV30_3D(QUERY_GET), 1);
190 PUSH_DATA (push, (q->report << 24) | q->qo[1]->hw->start);
191 }
192
193 if (q->enable) {
194 BEGIN_NV04(push, SUBC_3D(q->enable), 1);
195 PUSH_DATA (push, 0);
196 }
197 PUSH_KICK (push);
198 return true;
199 }
200
201 static boolean
nv30_query_result(struct pipe_context * pipe,struct pipe_query * pq,boolean wait,union pipe_query_result * result)202 nv30_query_result(struct pipe_context *pipe, struct pipe_query *pq,
203 boolean wait, union pipe_query_result *result)
204 {
205 struct nv30_screen *screen = nv30_screen(pipe->screen);
206 struct nv30_query *q = nv30_query(pq);
207 volatile uint32_t *ntfy0 = nv30_ntfy(screen, q->qo[0]);
208 volatile uint32_t *ntfy1 = nv30_ntfy(screen, q->qo[1]);
209
210 if (ntfy1) {
211 while (ntfy1[3] & 0xff000000) {
212 if (!wait)
213 return false;
214 }
215
216 switch (q->type) {
217 case PIPE_QUERY_TIMESTAMP:
218 q->result = *(uint64_t *)&ntfy1[0];
219 break;
220 case PIPE_QUERY_TIME_ELAPSED:
221 q->result = *(uint64_t *)&ntfy1[0] - *(uint64_t *)&ntfy0[0];
222 break;
223 default:
224 q->result = ntfy1[2];
225 break;
226 }
227
228 nv30_query_object_del(screen, &q->qo[0]);
229 nv30_query_object_del(screen, &q->qo[1]);
230 }
231
232 if (q->type == PIPE_QUERY_OCCLUSION_PREDICATE ||
233 q->type == PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE)
234 result->b = !!q->result;
235 else
236 result->u64 = q->result;
237 return true;
238 }
239
240 static void
nv40_query_render_condition(struct pipe_context * pipe,struct pipe_query * pq,boolean condition,enum pipe_render_cond_flag mode)241 nv40_query_render_condition(struct pipe_context *pipe,
242 struct pipe_query *pq,
243 boolean condition, enum pipe_render_cond_flag mode)
244 {
245 struct nv30_context *nv30 = nv30_context(pipe);
246 struct nv30_query *q = nv30_query(pq);
247 struct nouveau_pushbuf *push = nv30->base.pushbuf;
248
249 nv30->render_cond_query = pq;
250 nv30->render_cond_mode = mode;
251 nv30->render_cond_cond = condition;
252
253 if (!pq) {
254 BEGIN_NV04(push, SUBC_3D(0x1e98), 1);
255 PUSH_DATA (push, 0x01000000);
256 return;
257 }
258
259 if (mode == PIPE_RENDER_COND_WAIT ||
260 mode == PIPE_RENDER_COND_BY_REGION_WAIT) {
261 BEGIN_NV04(push, SUBC_3D(0x0110), 1);
262 PUSH_DATA (push, 0);
263 }
264
265 BEGIN_NV04(push, SUBC_3D(0x1e98), 1);
266 PUSH_DATA (push, 0x02000000 | q->qo[1]->hw->start);
267 }
268
269 static void
nv30_set_active_query_state(struct pipe_context * pipe,boolean enable)270 nv30_set_active_query_state(struct pipe_context *pipe, boolean enable)
271 {
272 }
273
274 void
nv30_query_init(struct pipe_context * pipe)275 nv30_query_init(struct pipe_context *pipe)
276 {
277 struct nouveau_object *eng3d = nv30_context(pipe)->screen->eng3d;
278
279 pipe->create_query = nv30_query_create;
280 pipe->destroy_query = nv30_query_destroy;
281 pipe->begin_query = nv30_query_begin;
282 pipe->end_query = nv30_query_end;
283 pipe->get_query_result = nv30_query_result;
284 pipe->set_active_query_state = nv30_set_active_query_state;
285 if (eng3d->oclass >= NV40_3D_CLASS)
286 pipe->render_condition = nv40_query_render_condition;
287 }
288