st/mesa: fix glCopyPixels bugs/crashes when src region need clipping
[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 struct nv40_screen *screen = nv40->screen;
45 struct nouveau_channel *chan = screen->base.channel;
46 struct nouveau_grobj *curie = screen->curie;
47
48 assert(q->type == PIPE_QUERY_OCCLUSION_COUNTER);
49
50 /* Happens when end_query() is called, then another begin_query()
51 * without querying the result in-between. For now we'll wait for
52 * the existing query to notify completion, but it could be better.
53 */
54 if (q->object) {
55 uint64_t tmp;
56 pipe->get_query_result(pipe, pq, 1, &tmp);
57 }
58
59 if (nouveau_resource_alloc(nv40->screen->query_heap, 1, NULL, &q->object))
60 assert(0);
61 nouveau_notifier_reset(nv40->screen->query, q->object->start);
62
63 BEGIN_RING(chan, curie, NV40TCL_QUERY_RESET, 1);
64 OUT_RING (chan, 1);
65 BEGIN_RING(chan, curie, NV40TCL_QUERY_UNK17CC, 1);
66 OUT_RING (chan, 1);
67
68 q->ready = FALSE;
69 }
70
71 static void
72 nv40_query_end(struct pipe_context *pipe, struct pipe_query *pq)
73 {
74 struct nv40_context *nv40 = nv40_context(pipe);
75 struct nv40_query *q = nv40_query(pq);
76 struct nv40_screen *screen = nv40->screen;
77 struct nouveau_channel *chan = screen->base.channel;
78 struct nouveau_grobj *curie = screen->curie;
79
80 BEGIN_RING(chan, curie, NV40TCL_QUERY_GET, 1);
81 OUT_RING (chan, (0x01 << NV40TCL_QUERY_GET_UNK24_SHIFT) |
82 ((q->object->start * 32) << NV40TCL_QUERY_GET_OFFSET_SHIFT));
83 FIRE_RING(chan);
84 }
85
86 static boolean
87 nv40_query_result(struct pipe_context *pipe, struct pipe_query *pq,
88 boolean wait, uint64_t *result)
89 {
90 struct nv40_context *nv40 = nv40_context(pipe);
91 struct nv40_query *q = nv40_query(pq);
92
93 assert(q->object && q->type == PIPE_QUERY_OCCLUSION_COUNTER);
94
95 if (!q->ready) {
96 unsigned status;
97
98 status = nouveau_notifier_status(nv40->screen->query,
99 q->object->start);
100 if (status != NV_NOTIFY_STATE_STATUS_COMPLETED) {
101 if (wait == FALSE)
102 return FALSE;
103 nouveau_notifier_wait_status(nv40->screen->query,
104 q->object->start,
105 NV_NOTIFY_STATE_STATUS_COMPLETED,
106 0);
107 }
108
109 q->result = nouveau_notifier_return_val(nv40->screen->query,
110 q->object->start);
111 q->ready = TRUE;
112 nouveau_resource_free(&q->object);
113 }
114
115 *result = q->result;
116 return TRUE;
117 }
118
119 void
120 nv40_init_query_functions(struct nv40_context *nv40)
121 {
122 nv40->pipe.create_query = nv40_query_create;
123 nv40->pipe.destroy_query = nv40_query_destroy;
124 nv40->pipe.begin_query = nv40_query_begin;
125 nv40->pipe.end_query = nv40_query_end;
126 nv40->pipe.get_query_result = nv40_query_result;
127 }