Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / gallium / drivers / nvfx / nvfx_query.c
1 #include "pipe/p_context.h"
2
3 #include "nvfx_context.h"
4
5 struct nvfx_query {
6         struct list_head list;
7         struct nouveau_resource *object;
8         unsigned type;
9         boolean ready;
10         uint64_t result;
11 };
12
13 static INLINE struct nvfx_query *
14 nvfx_query(struct pipe_query *pipe)
15 {
16         return (struct nvfx_query *)pipe;
17 }
18
19 static struct pipe_query *
20 nvfx_query_create(struct pipe_context *pipe, unsigned query_type)
21 {
22         struct nvfx_query *q;
23
24         q = CALLOC(1, sizeof(struct nvfx_query));
25         q->type = query_type;
26
27         assert(q->type == PIPE_QUERY_OCCLUSION_COUNTER);
28
29         return (struct pipe_query *)q;
30 }
31
32 static void
33 nvfx_query_destroy(struct pipe_context *pipe, struct pipe_query *pq)
34 {
35         struct nvfx_query *q = nvfx_query(pq);
36
37         if (q->object)
38         {
39                 nouveau_resource_free(&q->object);
40                 LIST_DEL(&q->list);
41         }
42         FREE(q);
43 }
44
45 static void
46 nvfx_query_begin(struct pipe_context *pipe, struct pipe_query *pq)
47 {
48         struct nvfx_context *nvfx = nvfx_context(pipe);
49         struct nvfx_query *q = nvfx_query(pq);
50         struct nvfx_screen *screen = nvfx->screen;
51         struct nouveau_channel *chan = screen->base.channel;
52         struct nouveau_grobj *eng3d = screen->eng3d;
53         uint64_t tmp;
54
55         assert(!nvfx->query);
56
57         /* Happens when end_query() is called, then another begin_query()
58          * without querying the result in-between.  For now we'll wait for
59          * the existing query to notify completion, but it could be better.
60          */
61         if (q->object)
62                 pipe->get_query_result(pipe, pq, 1, &tmp);
63
64         while (nouveau_resource_alloc(nvfx->screen->query_heap, 1, NULL, &q->object))
65         {
66                 struct nvfx_query* oldestq;
67                 assert(!LIST_IS_EMPTY(&nvfx->screen->query_list));
68                 oldestq = LIST_ENTRY(struct nvfx_query, nvfx->screen->query_list.next, list);
69                 pipe->get_query_result(pipe, (struct pipe_query*)oldestq, 1, &tmp);
70         }
71
72         LIST_ADDTAIL(&q->list, &nvfx->screen->query_list);
73
74         nouveau_notifier_reset(nvfx->screen->query, q->object->start);
75
76         BEGIN_RING(chan, eng3d, NV30_3D_QUERY_RESET, 1);
77         OUT_RING(chan, 1);
78         BEGIN_RING(chan, eng3d, NV30_3D_QUERY_ENABLE, 1);
79         OUT_RING(chan, 1);
80
81         q->ready = FALSE;
82
83         nvfx->query = pq;
84 }
85
86 static void
87 nvfx_query_end(struct pipe_context *pipe, struct pipe_query *pq)
88 {
89         struct nvfx_context *nvfx = nvfx_context(pipe);
90         struct nouveau_channel *chan = nvfx->screen->base.channel;
91         struct nouveau_grobj *eng3d = nvfx->screen->eng3d;
92         struct nvfx_query *q = nvfx_query(pq);
93
94         assert(nvfx->query == pq);
95
96         BEGIN_RING(chan, eng3d, NV30_3D_QUERY_GET, 1);
97         OUT_RING  (chan, (0x01 << NV30_3D_QUERY_GET_UNK24__SHIFT) |
98                    ((q->object->start * 32) << NV30_3D_QUERY_GET_OFFSET__SHIFT));
99         BEGIN_RING(chan, eng3d, NV30_3D_QUERY_ENABLE, 1);
100         OUT_RING(chan, 0);
101         FIRE_RING(chan);
102
103         nvfx->query = 0;
104 }
105
106 static boolean
107 nvfx_query_result(struct pipe_context *pipe, struct pipe_query *pq,
108                   boolean wait, void *vresult)
109 {
110         uint64_t *result = (uint64_t *)vresult;
111         struct nvfx_context *nvfx = nvfx_context(pipe);
112         struct nvfx_query *q = nvfx_query(pq);
113
114         if (!q->ready) {
115                 unsigned status;
116
117                 status = nouveau_notifier_status(nvfx->screen->query,
118                                                  q->object->start);
119                 if (status != NV_NOTIFY_STATE_STATUS_COMPLETED) {
120                         if (wait == FALSE)
121                                 return FALSE;
122
123                         nouveau_notifier_wait_status(nvfx->screen->query,
124                                         q->object->start,
125                                         NV_NOTIFY_STATE_STATUS_COMPLETED, 0);
126                 }
127
128                 q->result = nouveau_notifier_return_val(nvfx->screen->query,
129                                                         q->object->start);
130                 q->ready = TRUE;
131                 nouveau_resource_free(&q->object);
132                 LIST_DEL(&q->list);
133         }
134
135         *result = q->result;
136         return TRUE;
137 }
138
139 void
140 nvfx_init_query_functions(struct nvfx_context *nvfx)
141 {
142         nvfx->pipe.create_query = nvfx_query_create;
143         nvfx->pipe.destroy_query = nvfx_query_destroy;
144         nvfx->pipe.begin_query = nvfx_query_begin;
145         nvfx->pipe.end_query = nvfx_query_end;
146         nvfx->pipe.get_query_result = nvfx_query_result;
147 }