Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4358 | Serge | 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 "nouveau/nv_object.xml.h" |
||
27 | #include "nv30-40_3d.xml.h" |
||
28 | #include "nv30_screen.h" |
||
29 | #include "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 * |
||
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 |
||
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 * |
||
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 * |
||
102 | nv30_query(struct pipe_query *pipe) |
||
103 | { |
||
104 | return (struct nv30_query *)pipe; |
||
105 | } |
||
106 | |||
107 | static struct pipe_query * |
||
108 | nv30_query_create(struct pipe_context *pipe, unsigned type) |
||
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 | q->enable = NV30_3D_QUERY_ENABLE; |
||
124 | q->report = 1; |
||
125 | break; |
||
126 | case NV30_QUERY_ZCULL_0: |
||
127 | case NV30_QUERY_ZCULL_1: |
||
128 | case NV30_QUERY_ZCULL_2: |
||
129 | case NV30_QUERY_ZCULL_3: |
||
130 | q->enable = 0x1804; |
||
131 | q->report = 2 + (q->type - NV30_QUERY_ZCULL_0); |
||
132 | break; |
||
133 | default: |
||
134 | FREE(q); |
||
135 | return NULL; |
||
136 | } |
||
137 | |||
138 | return (struct pipe_query *)q; |
||
139 | } |
||
140 | |||
141 | static void |
||
142 | nv30_query_destroy(struct pipe_context *pipe, struct pipe_query *pq) |
||
143 | { |
||
144 | FREE(pq); |
||
145 | } |
||
146 | |||
147 | static void |
||
148 | nv30_query_begin(struct pipe_context *pipe, struct pipe_query *pq) |
||
149 | { |
||
150 | struct nv30_context *nv30 = nv30_context(pipe); |
||
151 | struct nv30_query *q = nv30_query(pq); |
||
152 | struct nouveau_pushbuf *push = nv30->base.pushbuf; |
||
153 | |||
154 | switch (q->type) { |
||
155 | case PIPE_QUERY_TIME_ELAPSED: |
||
156 | q->qo[0] = nv30_query_object_new(nv30->screen); |
||
157 | if (q->qo[0]) { |
||
158 | BEGIN_NV04(push, NV30_3D(QUERY_GET), 1); |
||
159 | PUSH_DATA (push, (q->report << 24) | q->qo[0]->hw->start); |
||
160 | } |
||
161 | break; |
||
162 | case PIPE_QUERY_TIMESTAMP: |
||
163 | return; |
||
164 | default: |
||
165 | BEGIN_NV04(push, NV30_3D(QUERY_RESET), 1); |
||
166 | PUSH_DATA (push, q->report); |
||
167 | break; |
||
168 | } |
||
169 | |||
170 | if (q->enable) { |
||
171 | BEGIN_NV04(push, SUBC_3D(q->enable), 1); |
||
172 | PUSH_DATA (push, 1); |
||
173 | } |
||
174 | } |
||
175 | |||
176 | static void |
||
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 | } |
||
196 | |||
197 | static boolean |
||
198 | nv30_query_result(struct pipe_context *pipe, struct pipe_query *pq, |
||
199 | boolean wait, union pipe_query_result *result) |
||
200 | { |
||
201 | struct nv30_screen *screen = nv30_screen(pipe->screen); |
||
202 | struct nv30_query *q = nv30_query(pq); |
||
203 | volatile uint32_t *ntfy0 = nv30_ntfy(screen, q->qo[0]); |
||
204 | volatile uint32_t *ntfy1 = nv30_ntfy(screen, q->qo[1]); |
||
205 | uint64_t *res64 = &result->u64; |
||
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 | *res64 = q->result; |
||
230 | return TRUE; |
||
231 | } |
||
232 | |||
233 | static void |
||
234 | nv40_query_render_condition(struct pipe_context *pipe, |
||
235 | struct pipe_query *pq, |
||
236 | boolean condition, uint mode) |
||
237 | { |
||
238 | struct nv30_context *nv30 = nv30_context(pipe); |
||
239 | struct nv30_query *q = nv30_query(pq); |
||
240 | struct nouveau_pushbuf *push = nv30->base.pushbuf; |
||
241 | |||
242 | nv30->render_cond_query = pq; |
||
243 | nv30->render_cond_mode = mode; |
||
244 | nv30->render_cond_cond = condition; |
||
245 | |||
246 | if (!pq) { |
||
247 | BEGIN_NV04(push, SUBC_3D(0x1e98), 1); |
||
248 | PUSH_DATA (push, 0x01000000); |
||
249 | return; |
||
250 | } |
||
251 | |||
252 | if (mode == PIPE_RENDER_COND_WAIT || |
||
253 | mode == PIPE_RENDER_COND_BY_REGION_WAIT) { |
||
254 | BEGIN_NV04(push, SUBC_3D(0x0110), 1); |
||
255 | PUSH_DATA (push, 0); |
||
256 | } |
||
257 | |||
258 | BEGIN_NV04(push, SUBC_3D(0x1e98), 1); |
||
259 | PUSH_DATA (push, 0x02000000 | q->qo[1]->hw->start); |
||
260 | } |
||
261 | |||
262 | void |
||
263 | nv30_query_init(struct pipe_context *pipe) |
||
264 | { |
||
265 | struct nouveau_object *eng3d = nv30_context(pipe)->screen->eng3d; |
||
266 | |||
267 | pipe->create_query = nv30_query_create; |
||
268 | pipe->destroy_query = nv30_query_destroy; |
||
269 | pipe->begin_query = nv30_query_begin; |
||
270 | pipe->end_query = nv30_query_end; |
||
271 | pipe->get_query_result = nv30_query_result; |
||
272 | if (eng3d->oclass >= NV40_3D_CLASS) |
||
273 | pipe->render_condition = nv40_query_render_condition; |
||
274 | }><>><> |