Merge branch 'mesa_7_5_branch'
[mesa.git] / src / gallium / drivers / nv40 / nv40_query.c
1 #include "pipe/p_context.h"
2
3 #include "nv40_context.h"
4
5 struct nv40_query {
6 struct nouveau_resource *object;
7 unsigned type;
8 boolean ready;
9 uint64_t result;
10 };
11
12 static INLINE struct nv40_query *
13 nv40_query(struct pipe_query *pipe)
14 {
15 return (struct nv40_query *)pipe;
16 }
17
18 static struct pipe_query *
19 nv40_query_create(struct pipe_context *pipe, unsigned query_type)
20 {
21 struct nv40_query *q;
22
23 q = CALLOC(1, sizeof(struct nv40_query));
24 q->type = query_type;
25
26 return (struct pipe_query *)q;
27 }
28
29 static void
30 nv40_query_destroy(struct pipe_context *pipe, struct pipe_query *pq)
31 {
32 struct nv40_query *q = nv40_query(pq);
33
34 if (q->object)
35 nouveau_resource_free(&q->object);
36 FREE(q);
37 }
38
39 static void
40 nv40_query_begin(struct pipe_context *pipe, struct pipe_query *pq)
41 {
42 struct nv40_context *nv40 = nv40_context(pipe);
43 struct nv40_query *q = nv40_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(nv40->screen->query_heap, 1, NULL, &q->object))
57 assert(0);
58 nouveau_notifier_reset(nv40->screen->query, q->object->start);
59
60 BEGIN_RING(curie, NV40TCL_QUERY_RESET, 1);
61 OUT_RING (1);
62 BEGIN_RING(curie, NV40TCL_QUERY_UNK17CC, 1);
63 OUT_RING (1);
64
65 q->ready = FALSE;
66 }
67
68 static void
69 nv40_query_end(struct pipe_context *pipe, struct pipe_query *pq)
70 {
71 struct nv40_context *nv40 = nv40_context(pipe);
72 struct nv40_query *q = nv40_query(pq);
73
74 BEGIN_RING(curie, NV40TCL_QUERY_GET, 1);
75 OUT_RING ((0x01 << NV40TCL_QUERY_GET_UNK24_SHIFT) |
76 ((q->object->start * 32) << NV40TCL_QUERY_GET_OFFSET_SHIFT));
77 FIRE_RING(NULL);
78 }
79
80 static boolean
81 nv40_query_result(struct pipe_context *pipe, struct pipe_query *pq,
82 boolean wait, uint64_t *result)
83 {
84 struct nv40_context *nv40 = nv40_context(pipe);
85 struct nv40_query *q = nv40_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(nv40->screen->query,
93 q->object->start);
94 if (status != NV_NOTIFY_STATE_STATUS_COMPLETED) {
95 if (wait == FALSE)
96 return FALSE;
97 nouveau_notifier_wait_status(nv40->screen->query,
98 q->object->start,
99 NV_NOTIFY_STATE_STATUS_COMPLETED,
100 0);
101 }
102
103 q->result = nouveau_notifier_return_val(nv40->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 nv40_init_query_functions(struct nv40_context *nv40)
115 {
116 nv40->pipe.create_query = nv40_query_create;
117 nv40->pipe.destroy_query = nv40_query_destroy;
118 nv40->pipe.begin_query = nv40_query_begin;
119 nv40->pipe.end_query = nv40_query_end;
120 nv40->pipe.get_query_result = nv40_query_result;
121 }