Merge commit 'origin/gallium-master-merge'
[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_context *nv40 = nv40_context(pipe);
33 struct nv40_query *q = nv40_query(pq);
34
35 if (q->object)
36 nv40->nvws->res_free(&q->object);
37 FREE(q);
38 }
39
40 static void
41 nv40_query_begin(struct pipe_context *pipe, struct pipe_query *pq)
42 {
43 struct nv40_context *nv40 = nv40_context(pipe);
44 struct nv40_query *q = nv40_query(pq);
45
46 assert(q->type == PIPE_QUERY_OCCLUSION_COUNTER);
47
48 /* Happens when end_query() is called, then another begin_query()
49 * without querying the result in-between. For now we'll wait for
50 * the existing query to notify completion, but it could be better.
51 */
52 if (q->object) {
53 uint64_t tmp;
54 pipe->get_query_result(pipe, pq, 1, &tmp);
55 }
56
57 if (nv40->nvws->res_alloc(nv40->screen->query_heap, 1, NULL, &q->object))
58 assert(0);
59 nv40->nvws->notifier_reset(nv40->screen->query, q->object->start);
60
61 BEGIN_RING(curie, NV40TCL_QUERY_RESET, 1);
62 OUT_RING (1);
63 BEGIN_RING(curie, NV40TCL_QUERY_UNK17CC, 1);
64 OUT_RING (1);
65
66 q->ready = FALSE;
67 }
68
69 static void
70 nv40_query_end(struct pipe_context *pipe, struct pipe_query *pq)
71 {
72 struct nv40_context *nv40 = nv40_context(pipe);
73 struct nv40_query *q = nv40_query(pq);
74
75 BEGIN_RING(curie, NV40TCL_QUERY_GET, 1);
76 OUT_RING ((0x01 << NV40TCL_QUERY_GET_UNK24_SHIFT) |
77 ((q->object->start * 32) << NV40TCL_QUERY_GET_OFFSET_SHIFT));
78 FIRE_RING(NULL);
79 }
80
81 static boolean
82 nv40_query_result(struct pipe_context *pipe, struct pipe_query *pq,
83 boolean wait, uint64_t *result)
84 {
85 struct nv40_context *nv40 = nv40_context(pipe);
86 struct nv40_query *q = nv40_query(pq);
87 struct nouveau_winsys *nvws = nv40->nvws;
88
89 assert(q->object && q->type == PIPE_QUERY_OCCLUSION_COUNTER);
90
91 if (!q->ready) {
92 unsigned status;
93
94 status = nvws->notifier_status(nv40->screen->query,
95 q->object->start);
96 if (status != NV_NOTIFY_STATE_STATUS_COMPLETED) {
97 if (wait == FALSE)
98 return FALSE;
99 nvws->notifier_wait(nv40->screen->query, q->object->start,
100 NV_NOTIFY_STATE_STATUS_COMPLETED,
101 0);
102 }
103
104 q->result = nvws->notifier_retval(nv40->screen->query,
105 q->object->start);
106 q->ready = TRUE;
107 nvws->res_free(&q->object);
108 }
109
110 *result = q->result;
111 return TRUE;
112 }
113
114 void
115 nv40_init_query_functions(struct nv40_context *nv40)
116 {
117 nv40->pipe.create_query = nv40_query_create;
118 nv40->pipe.destroy_query = nv40_query_destroy;
119 nv40->pipe.begin_query = nv40_query_begin;
120 nv40->pipe.end_query = nv40_query_end;
121 nv40->pipe.get_query_result = nv40_query_result;
122 }