OSDN Git Service

WIP nouveau: add locking
[android-x86/external-mesa.git] / src / gallium / drivers / nouveau / nv30 / nv30_query.c
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 *
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, 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       q->enable = NV30_3D_QUERY_ENABLE;
125       q->report = 1;
126       break;
127    case NV30_QUERY_ZCULL_0:
128    case NV30_QUERY_ZCULL_1:
129    case NV30_QUERY_ZCULL_2:
130    case NV30_QUERY_ZCULL_3:
131       q->enable = 0x1804;
132       q->report = 2 + (q->type - NV30_QUERY_ZCULL_0);
133       break;
134    default:
135       FREE(q);
136       return NULL;
137    }
138
139    return (struct pipe_query *)q;
140 }
141
142 static void
143 nv30_query_destroy(struct pipe_context *pipe, struct pipe_query *pq)
144 {
145    FREE(pq);
146 }
147
148 static boolean
149 nv30_query_begin(struct pipe_context *pipe, struct pipe_query *pq)
150 {
151    struct nv30_context *nv30 = nv30_context(pipe);
152    struct nv30_query *q = nv30_query(pq);
153    struct nouveau_pushbuf *push = nv30->base.pushbuf;
154
155    pipe_mutex_lock(nv30->screen->base.push_mutex);
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       break;
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    pipe_mutex_unlock(nv30->screen->base.push_mutex);
177    return true;
178 }
179
180 static bool
181 nv30_query_end(struct pipe_context *pipe, struct pipe_query *pq)
182 {
183    struct nv30_context *nv30 = nv30_context(pipe);
184    struct nv30_screen *screen = nv30->screen;
185    struct nv30_query *q = nv30_query(pq);
186    struct nouveau_pushbuf *push = nv30->base.pushbuf;
187
188    pipe_mutex_lock(nv30->screen->base.push_mutex);
189    q->qo[1] = nv30_query_object_new(screen);
190    if (q->qo[1]) {
191       BEGIN_NV04(push, NV30_3D(QUERY_GET), 1);
192       PUSH_DATA (push, (q->report << 24) | q->qo[1]->hw->start);
193    }
194
195    if (q->enable) {
196       BEGIN_NV04(push, SUBC_3D(q->enable), 1);
197       PUSH_DATA (push, 0);
198    }
199    PUSH_KICK (push);
200    pipe_mutex_unlock(nv30->screen->base.push_mutex);
201    return true;
202 }
203
204 static boolean
205 nv30_query_result(struct pipe_context *pipe, struct pipe_query *pq,
206                   boolean wait, union pipe_query_result *result)
207 {
208    struct nv30_screen *screen = nv30_screen(pipe->screen);
209    struct nv30_query *q = nv30_query(pq);
210    volatile uint32_t *ntfy0 = nv30_ntfy(screen, q->qo[0]);
211    volatile uint32_t *ntfy1 = nv30_ntfy(screen, q->qo[1]);
212
213    if (ntfy1) {
214       while (ntfy1[3] & 0xff000000) {
215          if (!wait)
216             return false;
217       }
218
219       switch (q->type) {
220       case PIPE_QUERY_TIMESTAMP:
221          q->result = *(uint64_t *)&ntfy1[0];
222          break;
223       case PIPE_QUERY_TIME_ELAPSED:
224          q->result = *(uint64_t *)&ntfy1[0] - *(uint64_t *)&ntfy0[0];
225          break;
226       default:
227          q->result = ntfy1[2];
228          break;
229       }
230
231       nv30_query_object_del(screen, &q->qo[0]);
232       nv30_query_object_del(screen, &q->qo[1]);
233    }
234
235    if (q->type == PIPE_QUERY_OCCLUSION_PREDICATE)
236       result->b = !!q->result;
237    else
238       result->u64 = q->result;
239    return true;
240 }
241
242 static void
243 nv40_query_render_condition(struct pipe_context *pipe,
244                             struct pipe_query *pq,
245                             boolean condition, uint mode)
246 {
247    struct nv30_context *nv30 = nv30_context(pipe);
248    struct nv30_query *q = nv30_query(pq);
249    struct nouveau_pushbuf *push = nv30->base.pushbuf;
250
251    nv30->render_cond_query = pq;
252    nv30->render_cond_mode = mode;
253    nv30->render_cond_cond = condition;
254
255    pipe_mutex_lock(nv30->screen->base.push_mutex);
256    if (!pq) {
257       BEGIN_NV04(push, SUBC_3D(0x1e98), 1);
258       PUSH_DATA (push, 0x01000000);
259       pipe_mutex_unlock(nv30->screen->base.push_mutex);
260       return;
261    }
262
263    if (mode == PIPE_RENDER_COND_WAIT ||
264        mode == PIPE_RENDER_COND_BY_REGION_WAIT) {
265       BEGIN_NV04(push, SUBC_3D(0x0110), 1);
266       PUSH_DATA (push, 0);
267    }
268
269    BEGIN_NV04(push, SUBC_3D(0x1e98), 1);
270    PUSH_DATA (push, 0x02000000 | q->qo[1]->hw->start);
271    pipe_mutex_unlock(nv30->screen->base.push_mutex);
272 }
273
274 static void
275 nv30_set_active_query_state(struct pipe_context *pipe, boolean enable)
276 {
277 }
278
279 void
280 nv30_query_init(struct pipe_context *pipe)
281 {
282    struct nouveau_object *eng3d = nv30_context(pipe)->screen->eng3d;
283
284    pipe->create_query = nv30_query_create;
285    pipe->destroy_query = nv30_query_destroy;
286    pipe->begin_query = nv30_query_begin;
287    pipe->end_query = nv30_query_end;
288    pipe->get_query_result = nv30_query_result;
289    pipe->set_active_query_state = nv30_set_active_query_state;
290    if (eng3d->oclass >= NV40_3D_CLASS)
291       pipe->render_condition = nv40_query_render_condition;
292 }