Merge branch 'mesa_7_5_branch'
[mesa.git] / src / gallium / drivers / nv30 / nv30_query.c
1 #include "pipe/p_context.h"
2
3 #include "nv30_context.h"
4
5 struct nv30_query {
6 struct nouveau_resource *object;
7 unsigned type;
8 boolean ready;
9 uint64_t result;
10 };
11
12 static INLINE struct nv30_query *
13 nv30_query(struct pipe_query *pipe)
14 {
15 return (struct nv30_query *)pipe;
16 }
17
18 static struct pipe_query *
19 nv30_query_create(struct pipe_context *pipe, unsigned query_type)
20 {
21 struct nv30_query *q;
22
23 q = CALLOC(1, sizeof(struct nv30_query));
24 q->type = query_type;
25
26 return (struct pipe_query *)q;
27 }
28
29 static void
30 nv30_query_destroy(struct pipe_context *pipe, struct pipe_query *pq)
31 {
32 struct nv30_query *q = nv30_query(pq);
33
34 if (q->object)
35 nouveau_resource_free(&q->object);
36 FREE(q);
37 }
38
39 static void
40 nv30_query_begin(struct pipe_context *pipe, struct pipe_query *pq)
41 {
42 struct nv30_context *nv30 = nv30_context(pipe);
43 struct nv30_query *q = nv30_query(pq);
44
45 assert(q->type == PIPE_QUERY_OCCLUSION_COUNTER);
46
47 /* Happens when end_query() is called, then another begin_query()
48 * without querying the result in-between. For now we'll wait for
49 * the existing query to notify completion, but it could be better.
50 */
51 if (q->object) {
52 uint64_t tmp;
53 pipe->get_query_result(pipe, pq, 1, &tmp);
54 }
55
56 if (nouveau_resource_alloc(nv30->screen->query_heap, 1, NULL, &q->object))
57 assert(0);
58 nouveau_notifier_reset(nv30->screen->query, q->object->start);
59
60 BEGIN_RING(rankine, NV34TCL_QUERY_RESET, 1);
61 OUT_RING (1);
62 BEGIN_RING(rankine, NV34TCL_QUERY_UNK17CC, 1);
63 OUT_RING (1);
64
65 q->ready = FALSE;
66 }
67
68 static void
69 nv30_query_end(struct pipe_context *pipe, struct pipe_query *pq)
70 {
71 struct nv30_context *nv30 = nv30_context(pipe);
72 struct nv30_query *q = nv30_query(pq);
73
74 BEGIN_RING(rankine, NV34TCL_QUERY_GET, 1);
75 OUT_RING ((0x01 << NV34TCL_QUERY_GET_UNK24_SHIFT) |
76 ((q->object->start * 32) << NV34TCL_QUERY_GET_OFFSET_SHIFT));
77 FIRE_RING(NULL);
78 }
79
80 static boolean
81 nv30_query_result(struct pipe_context *pipe, struct pipe_query *pq,
82 boolean wait, uint64_t *result)
83 {
84 struct nv30_context *nv30 = nv30_context(pipe);
85 struct nv30_query *q = nv30_query(pq);
86
87 assert(q->object && q->type == PIPE_QUERY_OCCLUSION_COUNTER);
88
89 if (!q->ready) {
90 unsigned status;
91
92 status = nouveau_notifier_status(nv30->screen->query,
93 q->object->start);
94 if (status != NV_NOTIFY_STATE_STATUS_COMPLETED) {
95 if (wait == FALSE)
96 return FALSE;
97
98 nouveau_notifier_wait_status(nv30->screen->query,
99 q->object->start,
100 NV_NOTIFY_STATE_STATUS_COMPLETED, 0);
101 }
102
103 q->result = nouveau_notifier_return_val(nv30->screen->query,
104 q->object->start);
105 q->ready = TRUE;
106 nouveau_resource_free(&q->object);
107 }
108
109 *result = q->result;
110 return TRUE;
111 }
112
113 void
114 nv30_init_query_functions(struct nv30_context *nv30)
115 {
116 nv30->pipe.create_query = nv30_query_create;
117 nv30->pipe.destroy_query = nv30_query_destroy;
118 nv30->pipe.begin_query = nv30_query_begin;
119 nv30->pipe.end_query = nv30_query_end;
120 nv30->pipe.get_query_result = nv30_query_result;
121 }