OSDN Git Service

nv50: add a header file for nv50_query
[android-x86/external-mesa.git] / src / gallium / drivers / nouveau / nv50 / nv50_query.c
1 /*
2  * Copyright 2011 Nouveau Project
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: Christoph Bumiller
23  */
24
25 #define NV50_PUSH_EXPLICIT_SPACE_CHECKING
26
27 #include "nv50/nv50_context.h"
28 #include "nv50/nv50_query.h"
29 #include "nv_object.xml.h"
30
31 #define NV50_QUERY_STATE_READY   0
32 #define NV50_QUERY_STATE_ACTIVE  1
33 #define NV50_QUERY_STATE_ENDED   2
34 #define NV50_QUERY_STATE_FLUSHED 3
35
36 /* XXX: Nested queries, and simultaneous queries on multiple gallium contexts
37  * (since we use only a single GPU channel per screen) will not work properly.
38  *
39  * The first is not that big of an issue because OpenGL does not allow nested
40  * queries anyway.
41  */
42
43 #define NV50_QUERY_ALLOC_SPACE 256
44
45 static bool
46 nv50_query_allocate(struct nv50_context *nv50, struct nv50_query *q, int size)
47 {
48    struct nv50_screen *screen = nv50->screen;
49    int ret;
50
51    if (q->bo) {
52       nouveau_bo_ref(NULL, &q->bo);
53       if (q->mm) {
54          if (q->state == NV50_QUERY_STATE_READY)
55             nouveau_mm_free(q->mm);
56          else
57             nouveau_fence_work(screen->base.fence.current, nouveau_mm_free_work,
58                                q->mm);
59       }
60    }
61    if (size) {
62       q->mm = nouveau_mm_allocate(screen->base.mm_GART, size, &q->bo, &q->base);
63       if (!q->bo)
64          return false;
65       q->offset = q->base;
66
67       ret = nouveau_bo_map(q->bo, 0, screen->base.client);
68       if (ret) {
69          nv50_query_allocate(nv50, q, 0);
70          return false;
71       }
72       q->data = (uint32_t *)((uint8_t *)q->bo->map + q->base);
73    }
74    return true;
75 }
76
77 static void
78 nv50_query_destroy(struct pipe_context *pipe, struct pipe_query *pq)
79 {
80    nv50_query_allocate(nv50_context(pipe), nv50_query(pq), 0);
81    nouveau_fence_ref(NULL, &nv50_query(pq)->fence);
82    FREE(nv50_query(pq));
83 }
84
85 static struct pipe_query *
86 nv50_query_create(struct pipe_context *pipe, unsigned type, unsigned index)
87 {
88    struct nv50_context *nv50 = nv50_context(pipe);
89    struct nv50_query *q;
90
91    q = CALLOC_STRUCT(nv50_query);
92    if (!q)
93       return NULL;
94
95    if (!nv50_query_allocate(nv50, q, NV50_QUERY_ALLOC_SPACE)) {
96       FREE(q);
97       return NULL;
98    }
99
100    q->is64bit = (type == PIPE_QUERY_PRIMITIVES_GENERATED ||
101                  type == PIPE_QUERY_PRIMITIVES_EMITTED ||
102                  type == PIPE_QUERY_SO_STATISTICS ||
103                  type == PIPE_QUERY_PIPELINE_STATISTICS);
104    q->type = type;
105
106    if (q->type == PIPE_QUERY_OCCLUSION_COUNTER) {
107       q->offset -= 32;
108       q->data -= 32 / sizeof(*q->data); /* we advance before query_begin ! */
109    }
110
111    return (struct pipe_query *)q;
112 }
113
114 static void
115 nv50_query_get(struct nouveau_pushbuf *push, struct nv50_query *q,
116                unsigned offset, uint32_t get)
117 {
118    offset += q->offset;
119
120    PUSH_SPACE(push, 5);
121    PUSH_REFN (push, q->bo, NOUVEAU_BO_GART | NOUVEAU_BO_WR);
122    BEGIN_NV04(push, NV50_3D(QUERY_ADDRESS_HIGH), 4);
123    PUSH_DATAh(push, q->bo->offset + offset);
124    PUSH_DATA (push, q->bo->offset + offset);
125    PUSH_DATA (push, q->sequence);
126    PUSH_DATA (push, get);
127 }
128
129 static boolean
130 nv50_query_begin(struct pipe_context *pipe, struct pipe_query *pq)
131 {
132    struct nv50_context *nv50 = nv50_context(pipe);
133    struct nouveau_pushbuf *push = nv50->base.pushbuf;
134    struct nv50_query *q = nv50_query(pq);
135
136    /* For occlusion queries we have to change the storage, because a previous
137     * query might set the initial render conition to false even *after* we re-
138     * initialized it to true.
139     */
140    if (q->type == PIPE_QUERY_OCCLUSION_COUNTER) {
141       q->offset += 32;
142       q->data += 32 / sizeof(*q->data);
143       if (q->offset - q->base == NV50_QUERY_ALLOC_SPACE)
144          nv50_query_allocate(nv50, q, NV50_QUERY_ALLOC_SPACE);
145
146       /* XXX: can we do this with the GPU, and sync with respect to a previous
147        *  query ?
148        */
149       q->data[0] = q->sequence; /* initialize sequence */
150       q->data[1] = 1; /* initial render condition = true */
151       q->data[4] = q->sequence + 1; /* for comparison COND_MODE */
152       q->data[5] = 0;
153    }
154    if (!q->is64bit)
155       q->data[0] = q->sequence++; /* the previously used one */
156
157    switch (q->type) {
158    case PIPE_QUERY_OCCLUSION_COUNTER:
159       q->nesting = nv50->screen->num_occlusion_queries_active++;
160       if (q->nesting) {
161          nv50_query_get(push, q, 0x10, 0x0100f002);
162       } else {
163          PUSH_SPACE(push, 4);
164          BEGIN_NV04(push, NV50_3D(COUNTER_RESET), 1);
165          PUSH_DATA (push, NV50_3D_COUNTER_RESET_SAMPLECNT);
166          BEGIN_NV04(push, NV50_3D(SAMPLECNT_ENABLE), 1);
167          PUSH_DATA (push, 1);
168       }
169       break;
170    case PIPE_QUERY_PRIMITIVES_GENERATED:
171       nv50_query_get(push, q, 0x10, 0x06805002);
172       break;
173    case PIPE_QUERY_PRIMITIVES_EMITTED:
174       nv50_query_get(push, q, 0x10, 0x05805002);
175       break;
176    case PIPE_QUERY_SO_STATISTICS:
177       nv50_query_get(push, q, 0x20, 0x05805002);
178       nv50_query_get(push, q, 0x30, 0x06805002);
179       break;
180    case PIPE_QUERY_PIPELINE_STATISTICS:
181       nv50_query_get(push, q, 0x80, 0x00801002); /* VFETCH, VERTICES */
182       nv50_query_get(push, q, 0x90, 0x01801002); /* VFETCH, PRIMS */
183       nv50_query_get(push, q, 0xa0, 0x02802002); /* VP, LAUNCHES */
184       nv50_query_get(push, q, 0xb0, 0x03806002); /* GP, LAUNCHES */
185       nv50_query_get(push, q, 0xc0, 0x04806002); /* GP, PRIMS_OUT */
186       nv50_query_get(push, q, 0xd0, 0x07804002); /* RAST, PRIMS_IN */
187       nv50_query_get(push, q, 0xe0, 0x08804002); /* RAST, PRIMS_OUT */
188       nv50_query_get(push, q, 0xf0, 0x0980a002); /* ROP, PIXELS */
189       break;
190    case PIPE_QUERY_TIME_ELAPSED:
191       nv50_query_get(push, q, 0x10, 0x00005002);
192       break;
193    default:
194       break;
195    }
196    q->state = NV50_QUERY_STATE_ACTIVE;
197    return true;
198 }
199
200 static void
201 nv50_query_end(struct pipe_context *pipe, struct pipe_query *pq)
202 {
203    struct nv50_context *nv50 = nv50_context(pipe);
204    struct nouveau_pushbuf *push = nv50->base.pushbuf;
205    struct nv50_query *q = nv50_query(pq);
206
207    q->state = NV50_QUERY_STATE_ENDED;
208
209    switch (q->type) {
210    case PIPE_QUERY_OCCLUSION_COUNTER:
211       nv50_query_get(push, q, 0, 0x0100f002);
212       if (--nv50->screen->num_occlusion_queries_active == 0) {
213          PUSH_SPACE(push, 2);
214          BEGIN_NV04(push, NV50_3D(SAMPLECNT_ENABLE), 1);
215          PUSH_DATA (push, 0);
216       }
217       break;
218    case PIPE_QUERY_PRIMITIVES_GENERATED:
219       nv50_query_get(push, q, 0, 0x06805002);
220       break;
221    case PIPE_QUERY_PRIMITIVES_EMITTED:
222       nv50_query_get(push, q, 0, 0x05805002);
223       break;
224    case PIPE_QUERY_SO_STATISTICS:
225       nv50_query_get(push, q, 0x00, 0x05805002);
226       nv50_query_get(push, q, 0x10, 0x06805002);
227       break;
228    case PIPE_QUERY_PIPELINE_STATISTICS:
229       nv50_query_get(push, q, 0x00, 0x00801002); /* VFETCH, VERTICES */
230       nv50_query_get(push, q, 0x10, 0x01801002); /* VFETCH, PRIMS */
231       nv50_query_get(push, q, 0x20, 0x02802002); /* VP, LAUNCHES */
232       nv50_query_get(push, q, 0x30, 0x03806002); /* GP, LAUNCHES */
233       nv50_query_get(push, q, 0x40, 0x04806002); /* GP, PRIMS_OUT */
234       nv50_query_get(push, q, 0x50, 0x07804002); /* RAST, PRIMS_IN */
235       nv50_query_get(push, q, 0x60, 0x08804002); /* RAST, PRIMS_OUT */
236       nv50_query_get(push, q, 0x70, 0x0980a002); /* ROP, PIXELS */
237       break;
238    case PIPE_QUERY_TIMESTAMP:
239       q->sequence++;
240       /* fall through */
241    case PIPE_QUERY_TIME_ELAPSED:
242       nv50_query_get(push, q, 0, 0x00005002);
243       break;
244    case PIPE_QUERY_GPU_FINISHED:
245       q->sequence++;
246       nv50_query_get(push, q, 0, 0x1000f010);
247       break;
248    case NVA0_QUERY_STREAM_OUTPUT_BUFFER_OFFSET:
249       q->sequence++;
250       nv50_query_get(push, q, 0, 0x0d005002 | (q->index << 5));
251       break;
252    case PIPE_QUERY_TIMESTAMP_DISJOINT:
253       /* This query is not issued on GPU because disjoint is forced to false */
254       q->state = NV50_QUERY_STATE_READY;
255       break;
256    default:
257       assert(0);
258       break;
259    }
260
261    if (q->is64bit)
262       nouveau_fence_ref(nv50->screen->base.fence.current, &q->fence);
263 }
264
265 static inline void
266 nv50_query_update(struct nv50_query *q)
267 {
268    if (q->is64bit) {
269       if (nouveau_fence_signalled(q->fence))
270          q->state = NV50_QUERY_STATE_READY;
271    } else {
272       if (q->data[0] == q->sequence)
273          q->state = NV50_QUERY_STATE_READY;
274    }
275 }
276
277 static boolean
278 nv50_query_result(struct pipe_context *pipe, struct pipe_query *pq,
279                   boolean wait, union pipe_query_result *result)
280 {
281    struct nv50_context *nv50 = nv50_context(pipe);
282    struct nv50_query *q = nv50_query(pq);
283    uint64_t *res64 = (uint64_t *)result;
284    uint32_t *res32 = (uint32_t *)result;
285    uint8_t *res8 = (uint8_t *)result;
286    uint64_t *data64 = (uint64_t *)q->data;
287    int i;
288
289    if (q->state != NV50_QUERY_STATE_READY)
290       nv50_query_update(q);
291
292    if (q->state != NV50_QUERY_STATE_READY) {
293       if (!wait) {
294          /* for broken apps that spin on GL_QUERY_RESULT_AVAILABLE */
295          if (q->state != NV50_QUERY_STATE_FLUSHED) {
296             q->state = NV50_QUERY_STATE_FLUSHED;
297             PUSH_KICK(nv50->base.pushbuf);
298          }
299          return false;
300       }
301       if (nouveau_bo_wait(q->bo, NOUVEAU_BO_RD, nv50->screen->base.client))
302          return false;
303    }
304    q->state = NV50_QUERY_STATE_READY;
305
306    switch (q->type) {
307    case PIPE_QUERY_GPU_FINISHED:
308       res8[0] = true;
309       break;
310    case PIPE_QUERY_OCCLUSION_COUNTER: /* u32 sequence, u32 count, u64 time */
311       res64[0] = q->data[1] - q->data[5];
312       break;
313    case PIPE_QUERY_PRIMITIVES_GENERATED: /* u64 count, u64 time */
314    case PIPE_QUERY_PRIMITIVES_EMITTED: /* u64 count, u64 time */
315       res64[0] = data64[0] - data64[2];
316       break;
317    case PIPE_QUERY_SO_STATISTICS:
318       res64[0] = data64[0] - data64[4];
319       res64[1] = data64[2] - data64[6];
320       break;
321    case PIPE_QUERY_PIPELINE_STATISTICS:
322       for (i = 0; i < 8; ++i)
323          res64[i] = data64[i * 2] - data64[16 + i * 2];
324       break;
325    case PIPE_QUERY_TIMESTAMP:
326       res64[0] = data64[1];
327       break;
328    case PIPE_QUERY_TIMESTAMP_DISJOINT:
329       res64[0] = 1000000000;
330       res8[8] = false;
331       break;
332    case PIPE_QUERY_TIME_ELAPSED:
333       res64[0] = data64[1] - data64[3];
334       break;
335    case NVA0_QUERY_STREAM_OUTPUT_BUFFER_OFFSET:
336       res32[0] = q->data[1];
337       break;
338    default:
339       return false;
340    }
341
342    return true;
343 }
344
345 void
346 nv84_query_fifo_wait(struct nouveau_pushbuf *push, struct nv50_query *q)
347 {
348    unsigned offset = q->offset;
349
350    PUSH_SPACE(push, 5);
351    PUSH_REFN (push, q->bo, NOUVEAU_BO_GART | NOUVEAU_BO_RD);
352    BEGIN_NV04(push, SUBC_3D(NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH), 4);
353    PUSH_DATAh(push, q->bo->offset + offset);
354    PUSH_DATA (push, q->bo->offset + offset);
355    PUSH_DATA (push, q->sequence);
356    PUSH_DATA (push, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL);
357 }
358
359 static void
360 nv50_render_condition(struct pipe_context *pipe,
361                       struct pipe_query *pq,
362                       boolean condition, uint mode)
363 {
364    struct nv50_context *nv50 = nv50_context(pipe);
365    struct nouveau_pushbuf *push = nv50->base.pushbuf;
366    struct nv50_query *q;
367    uint32_t cond;
368    bool wait =
369       mode != PIPE_RENDER_COND_NO_WAIT &&
370       mode != PIPE_RENDER_COND_BY_REGION_NO_WAIT;
371
372    if (!pq) {
373       cond = NV50_3D_COND_MODE_ALWAYS;
374    }
375    else {
376       q = nv50_query(pq);
377       /* NOTE: comparison of 2 queries only works if both have completed */
378       switch (q->type) {
379       case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
380          cond = condition ? NV50_3D_COND_MODE_EQUAL :
381                             NV50_3D_COND_MODE_NOT_EQUAL;
382          wait = true;
383          break;
384       case PIPE_QUERY_OCCLUSION_COUNTER:
385       case PIPE_QUERY_OCCLUSION_PREDICATE:
386          if (likely(!condition)) {
387             if (unlikely(q->nesting))
388                cond = wait ? NV50_3D_COND_MODE_NOT_EQUAL :
389                              NV50_3D_COND_MODE_ALWAYS;
390             else
391                cond = NV50_3D_COND_MODE_RES_NON_ZERO;
392          } else {
393             cond = wait ? NV50_3D_COND_MODE_EQUAL : NV50_3D_COND_MODE_ALWAYS;
394          }
395          break;
396       default:
397          assert(!"render condition query not a predicate");
398          cond = NV50_3D_COND_MODE_ALWAYS;
399          break;
400       }
401    }
402
403    nv50->cond_query = pq;
404    nv50->cond_cond = condition;
405    nv50->cond_condmode = cond;
406    nv50->cond_mode = mode;
407
408    if (!pq) {
409       PUSH_SPACE(push, 2);
410       BEGIN_NV04(push, NV50_3D(COND_MODE), 1);
411       PUSH_DATA (push, cond);
412       return;
413    }
414
415    PUSH_SPACE(push, 9);
416
417    if (wait) {
418       BEGIN_NV04(push, SUBC_3D(NV50_GRAPH_SERIALIZE), 1);
419       PUSH_DATA (push, 0);
420    }
421
422    PUSH_REFN (push, q->bo, NOUVEAU_BO_GART | NOUVEAU_BO_RD);
423    BEGIN_NV04(push, NV50_3D(COND_ADDRESS_HIGH), 3);
424    PUSH_DATAh(push, q->bo->offset + q->offset);
425    PUSH_DATA (push, q->bo->offset + q->offset);
426    PUSH_DATA (push, cond);
427
428    BEGIN_NV04(push, NV50_2D(COND_ADDRESS_HIGH), 2);
429    PUSH_DATAh(push, q->bo->offset + q->offset);
430    PUSH_DATA (push, q->bo->offset + q->offset);
431 }
432
433 void
434 nv50_query_pushbuf_submit(struct nouveau_pushbuf *push, uint16_t method,
435                           struct nv50_query *q, unsigned result_offset)
436 {
437    nv50_query_update(q);
438    if (q->state != NV50_QUERY_STATE_READY)
439       nouveau_bo_wait(q->bo, NOUVEAU_BO_RD, push->client);
440    q->state = NV50_QUERY_STATE_READY;
441
442    BEGIN_NV04(push, SUBC_3D(method), 1);
443    PUSH_DATA (push, q->data[result_offset / 4]);
444 }
445
446 void
447 nva0_so_target_save_offset(struct pipe_context *pipe,
448                            struct pipe_stream_output_target *ptarg,
449                            unsigned index, bool serialize)
450 {
451    struct nv50_so_target *targ = nv50_so_target(ptarg);
452
453    if (serialize) {
454       struct nouveau_pushbuf *push = nv50_context(pipe)->base.pushbuf;
455       PUSH_SPACE(push, 2);
456       BEGIN_NV04(push, SUBC_3D(NV50_GRAPH_SERIALIZE), 1);
457       PUSH_DATA (push, 0);
458    }
459
460    nv50_query(targ->pq)->index = index;
461    nv50_query_end(pipe, targ->pq);
462 }
463
464 void
465 nv50_init_query_functions(struct nv50_context *nv50)
466 {
467    struct pipe_context *pipe = &nv50->base.pipe;
468
469    pipe->create_query = nv50_query_create;
470    pipe->destroy_query = nv50_query_destroy;
471    pipe->begin_query = nv50_query_begin;
472    pipe->end_query = nv50_query_end;
473    pipe->get_query_result = nv50_query_result;
474    pipe->render_condition = nv50_render_condition;
475 }