1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright 2012 Red Hat Inc.
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
12bf215546Sopenharmony_ci * all copies or substantial portions of the Software.
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18bf215546Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19bf215546Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20bf215546Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
21bf215546Sopenharmony_ci *
22bf215546Sopenharmony_ci * Authors: Ben Skeggs
23bf215546Sopenharmony_ci *
24bf215546Sopenharmony_ci */
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci#include "nv_object.xml.h"
27bf215546Sopenharmony_ci#include "nv30/nv30-40_3d.xml.h"
28bf215546Sopenharmony_ci#include "nv30/nv30_screen.h"
29bf215546Sopenharmony_ci#include "nv30/nv30_context.h"
30bf215546Sopenharmony_ci
31bf215546Sopenharmony_cistruct nv30_query_object {
32bf215546Sopenharmony_ci   struct list_head list;
33bf215546Sopenharmony_ci   struct nouveau_heap *hw;
34bf215546Sopenharmony_ci};
35bf215546Sopenharmony_ci
36bf215546Sopenharmony_cistatic volatile void *
37bf215546Sopenharmony_cinv30_ntfy(struct nv30_screen *screen, struct nv30_query_object *qo)
38bf215546Sopenharmony_ci{
39bf215546Sopenharmony_ci   struct nv04_notify *query = screen->query->data;
40bf215546Sopenharmony_ci   struct nouveau_bo *notify = screen->notify;
41bf215546Sopenharmony_ci   volatile void *ntfy = NULL;
42bf215546Sopenharmony_ci
43bf215546Sopenharmony_ci   if (qo && qo->hw)
44bf215546Sopenharmony_ci      ntfy = (char *)notify->map + query->offset + qo->hw->start;
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_ci   return ntfy;
47bf215546Sopenharmony_ci}
48bf215546Sopenharmony_ci
49bf215546Sopenharmony_cistatic void
50bf215546Sopenharmony_cinv30_query_object_del(struct nv30_screen *screen, struct nv30_query_object **po)
51bf215546Sopenharmony_ci{
52bf215546Sopenharmony_ci   struct nv30_query_object *qo = *po; *po = NULL;
53bf215546Sopenharmony_ci   if (qo) {
54bf215546Sopenharmony_ci      volatile uint32_t *ntfy = nv30_ntfy(screen, qo);
55bf215546Sopenharmony_ci      while (ntfy[3] & 0xff000000) {
56bf215546Sopenharmony_ci      }
57bf215546Sopenharmony_ci      nouveau_heap_free(&qo->hw);
58bf215546Sopenharmony_ci      list_del(&qo->list);
59bf215546Sopenharmony_ci      FREE(qo);
60bf215546Sopenharmony_ci   }
61bf215546Sopenharmony_ci}
62bf215546Sopenharmony_ci
63bf215546Sopenharmony_cistatic struct nv30_query_object *
64bf215546Sopenharmony_cinv30_query_object_new(struct nv30_screen *screen)
65bf215546Sopenharmony_ci{
66bf215546Sopenharmony_ci   struct nv30_query_object *oq, *qo = CALLOC_STRUCT(nv30_query_object);
67bf215546Sopenharmony_ci   volatile uint32_t *ntfy;
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_ci   if (!qo)
70bf215546Sopenharmony_ci      return NULL;
71bf215546Sopenharmony_ci
72bf215546Sopenharmony_ci   /* allocate a new hw query object, if no hw objects left we need to
73bf215546Sopenharmony_ci    * spin waiting for one to become free
74bf215546Sopenharmony_ci    */
75bf215546Sopenharmony_ci   while (nouveau_heap_alloc(screen->query_heap, 32, NULL, &qo->hw)) {
76bf215546Sopenharmony_ci      oq = list_first_entry(&screen->queries, struct nv30_query_object, list);
77bf215546Sopenharmony_ci      nv30_query_object_del(screen, &oq);
78bf215546Sopenharmony_ci   }
79bf215546Sopenharmony_ci
80bf215546Sopenharmony_ci   list_addtail(&qo->list, &screen->queries);
81bf215546Sopenharmony_ci
82bf215546Sopenharmony_ci   ntfy = nv30_ntfy(screen, qo);
83bf215546Sopenharmony_ci   ntfy[0] = 0x00000000;
84bf215546Sopenharmony_ci   ntfy[1] = 0x00000000;
85bf215546Sopenharmony_ci   ntfy[2] = 0x00000000;
86bf215546Sopenharmony_ci   ntfy[3] = 0x01000000;
87bf215546Sopenharmony_ci   return qo;
88bf215546Sopenharmony_ci}
89bf215546Sopenharmony_ci
90bf215546Sopenharmony_cistruct nv30_query {
91bf215546Sopenharmony_ci   struct nv30_query_object *qo[2];
92bf215546Sopenharmony_ci   unsigned type;
93bf215546Sopenharmony_ci   uint32_t report;
94bf215546Sopenharmony_ci   uint32_t enable;
95bf215546Sopenharmony_ci   uint64_t result;
96bf215546Sopenharmony_ci};
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_cistatic inline struct nv30_query *
99bf215546Sopenharmony_cinv30_query(struct pipe_query *pipe)
100bf215546Sopenharmony_ci{
101bf215546Sopenharmony_ci   return (struct nv30_query *)pipe;
102bf215546Sopenharmony_ci}
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_cistatic struct pipe_query *
105bf215546Sopenharmony_cinv30_query_create(struct pipe_context *pipe, unsigned type, unsigned index)
106bf215546Sopenharmony_ci{
107bf215546Sopenharmony_ci   struct nv30_query *q = CALLOC_STRUCT(nv30_query);
108bf215546Sopenharmony_ci   if (!q)
109bf215546Sopenharmony_ci      return NULL;
110bf215546Sopenharmony_ci
111bf215546Sopenharmony_ci   q->type = type;
112bf215546Sopenharmony_ci
113bf215546Sopenharmony_ci   switch (q->type) {
114bf215546Sopenharmony_ci   case PIPE_QUERY_TIMESTAMP:
115bf215546Sopenharmony_ci   case PIPE_QUERY_TIME_ELAPSED:
116bf215546Sopenharmony_ci      q->enable = 0x0000;
117bf215546Sopenharmony_ci      q->report = 1;
118bf215546Sopenharmony_ci      break;
119bf215546Sopenharmony_ci   case PIPE_QUERY_OCCLUSION_COUNTER:
120bf215546Sopenharmony_ci   case PIPE_QUERY_OCCLUSION_PREDICATE:
121bf215546Sopenharmony_ci   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
122bf215546Sopenharmony_ci      q->enable = NV30_3D_QUERY_ENABLE;
123bf215546Sopenharmony_ci      q->report = 1;
124bf215546Sopenharmony_ci      break;
125bf215546Sopenharmony_ci   case NV30_QUERY_ZCULL_0:
126bf215546Sopenharmony_ci   case NV30_QUERY_ZCULL_1:
127bf215546Sopenharmony_ci   case NV30_QUERY_ZCULL_2:
128bf215546Sopenharmony_ci   case NV30_QUERY_ZCULL_3:
129bf215546Sopenharmony_ci      q->enable = 0x1804;
130bf215546Sopenharmony_ci      q->report = 2 + (q->type - NV30_QUERY_ZCULL_0);
131bf215546Sopenharmony_ci      break;
132bf215546Sopenharmony_ci   default:
133bf215546Sopenharmony_ci      FREE(q);
134bf215546Sopenharmony_ci      return NULL;
135bf215546Sopenharmony_ci   }
136bf215546Sopenharmony_ci
137bf215546Sopenharmony_ci   return (struct pipe_query *)q;
138bf215546Sopenharmony_ci}
139bf215546Sopenharmony_ci
140bf215546Sopenharmony_cistatic void
141bf215546Sopenharmony_cinv30_query_destroy(struct pipe_context *pipe, struct pipe_query *pq)
142bf215546Sopenharmony_ci{
143bf215546Sopenharmony_ci   FREE(pq);
144bf215546Sopenharmony_ci}
145bf215546Sopenharmony_ci
146bf215546Sopenharmony_cistatic bool
147bf215546Sopenharmony_cinv30_query_begin(struct pipe_context *pipe, struct pipe_query *pq)
148bf215546Sopenharmony_ci{
149bf215546Sopenharmony_ci   struct nv30_context *nv30 = nv30_context(pipe);
150bf215546Sopenharmony_ci   struct nv30_query *q = nv30_query(pq);
151bf215546Sopenharmony_ci   struct nouveau_pushbuf *push = nv30->base.pushbuf;
152bf215546Sopenharmony_ci
153bf215546Sopenharmony_ci   switch (q->type) {
154bf215546Sopenharmony_ci   case PIPE_QUERY_TIME_ELAPSED:
155bf215546Sopenharmony_ci      q->qo[0] = nv30_query_object_new(nv30->screen);
156bf215546Sopenharmony_ci      if (q->qo[0]) {
157bf215546Sopenharmony_ci         BEGIN_NV04(push, NV30_3D(QUERY_GET), 1);
158bf215546Sopenharmony_ci         PUSH_DATA (push, (q->report << 24) | q->qo[0]->hw->start);
159bf215546Sopenharmony_ci      }
160bf215546Sopenharmony_ci      break;
161bf215546Sopenharmony_ci   case PIPE_QUERY_TIMESTAMP:
162bf215546Sopenharmony_ci      return true;
163bf215546Sopenharmony_ci   default:
164bf215546Sopenharmony_ci      BEGIN_NV04(push, NV30_3D(QUERY_RESET), 1);
165bf215546Sopenharmony_ci      PUSH_DATA (push, q->report);
166bf215546Sopenharmony_ci      break;
167bf215546Sopenharmony_ci   }
168bf215546Sopenharmony_ci
169bf215546Sopenharmony_ci   if (q->enable) {
170bf215546Sopenharmony_ci      BEGIN_NV04(push, SUBC_3D(q->enable), 1);
171bf215546Sopenharmony_ci      PUSH_DATA (push, 1);
172bf215546Sopenharmony_ci   }
173bf215546Sopenharmony_ci   return true;
174bf215546Sopenharmony_ci}
175bf215546Sopenharmony_ci
176bf215546Sopenharmony_cistatic bool
177bf215546Sopenharmony_cinv30_query_end(struct pipe_context *pipe, struct pipe_query *pq)
178bf215546Sopenharmony_ci{
179bf215546Sopenharmony_ci   struct nv30_context *nv30 = nv30_context(pipe);
180bf215546Sopenharmony_ci   struct nv30_screen *screen = nv30->screen;
181bf215546Sopenharmony_ci   struct nv30_query *q = nv30_query(pq);
182bf215546Sopenharmony_ci   struct nouveau_pushbuf *push = nv30->base.pushbuf;
183bf215546Sopenharmony_ci
184bf215546Sopenharmony_ci   q->qo[1] = nv30_query_object_new(screen);
185bf215546Sopenharmony_ci   if (q->qo[1]) {
186bf215546Sopenharmony_ci      BEGIN_NV04(push, NV30_3D(QUERY_GET), 1);
187bf215546Sopenharmony_ci      PUSH_DATA (push, (q->report << 24) | q->qo[1]->hw->start);
188bf215546Sopenharmony_ci   }
189bf215546Sopenharmony_ci
190bf215546Sopenharmony_ci   if (q->enable) {
191bf215546Sopenharmony_ci      BEGIN_NV04(push, SUBC_3D(q->enable), 1);
192bf215546Sopenharmony_ci      PUSH_DATA (push, 0);
193bf215546Sopenharmony_ci   }
194bf215546Sopenharmony_ci   PUSH_KICK (push);
195bf215546Sopenharmony_ci   return true;
196bf215546Sopenharmony_ci}
197bf215546Sopenharmony_ci
198bf215546Sopenharmony_cistatic bool
199bf215546Sopenharmony_cinv30_query_result(struct pipe_context *pipe, struct pipe_query *pq,
200bf215546Sopenharmony_ci                  bool wait, union pipe_query_result *result)
201bf215546Sopenharmony_ci{
202bf215546Sopenharmony_ci   struct nv30_screen *screen = nv30_screen(pipe->screen);
203bf215546Sopenharmony_ci   struct nv30_query *q = nv30_query(pq);
204bf215546Sopenharmony_ci   volatile uint32_t *ntfy0 = nv30_ntfy(screen, q->qo[0]);
205bf215546Sopenharmony_ci   volatile uint32_t *ntfy1 = nv30_ntfy(screen, q->qo[1]);
206bf215546Sopenharmony_ci
207bf215546Sopenharmony_ci   if (ntfy1) {
208bf215546Sopenharmony_ci      while (ntfy1[3] & 0xff000000) {
209bf215546Sopenharmony_ci         if (!wait)
210bf215546Sopenharmony_ci            return false;
211bf215546Sopenharmony_ci      }
212bf215546Sopenharmony_ci
213bf215546Sopenharmony_ci      switch (q->type) {
214bf215546Sopenharmony_ci      case PIPE_QUERY_TIMESTAMP:
215bf215546Sopenharmony_ci         q->result = *(uint64_t *)&ntfy1[0];
216bf215546Sopenharmony_ci         break;
217bf215546Sopenharmony_ci      case PIPE_QUERY_TIME_ELAPSED:
218bf215546Sopenharmony_ci         q->result = *(uint64_t *)&ntfy1[0] - *(uint64_t *)&ntfy0[0];
219bf215546Sopenharmony_ci         break;
220bf215546Sopenharmony_ci      default:
221bf215546Sopenharmony_ci         q->result = ntfy1[2];
222bf215546Sopenharmony_ci         break;
223bf215546Sopenharmony_ci      }
224bf215546Sopenharmony_ci
225bf215546Sopenharmony_ci      nv30_query_object_del(screen, &q->qo[0]);
226bf215546Sopenharmony_ci      nv30_query_object_del(screen, &q->qo[1]);
227bf215546Sopenharmony_ci   }
228bf215546Sopenharmony_ci
229bf215546Sopenharmony_ci   if (q->type == PIPE_QUERY_OCCLUSION_PREDICATE ||
230bf215546Sopenharmony_ci       q->type == PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE)
231bf215546Sopenharmony_ci      result->b = !!q->result;
232bf215546Sopenharmony_ci   else
233bf215546Sopenharmony_ci      result->u64 = q->result;
234bf215546Sopenharmony_ci   return true;
235bf215546Sopenharmony_ci}
236bf215546Sopenharmony_ci
237bf215546Sopenharmony_cistatic void
238bf215546Sopenharmony_cinv40_query_render_condition(struct pipe_context *pipe,
239bf215546Sopenharmony_ci                            struct pipe_query *pq,
240bf215546Sopenharmony_ci                            bool condition, enum pipe_render_cond_flag mode)
241bf215546Sopenharmony_ci{
242bf215546Sopenharmony_ci   struct nv30_context *nv30 = nv30_context(pipe);
243bf215546Sopenharmony_ci   struct nv30_query *q = nv30_query(pq);
244bf215546Sopenharmony_ci   struct nouveau_pushbuf *push = nv30->base.pushbuf;
245bf215546Sopenharmony_ci
246bf215546Sopenharmony_ci   nv30->render_cond_query = pq;
247bf215546Sopenharmony_ci   nv30->render_cond_mode = mode;
248bf215546Sopenharmony_ci   nv30->render_cond_cond = condition;
249bf215546Sopenharmony_ci
250bf215546Sopenharmony_ci   if (!pq) {
251bf215546Sopenharmony_ci      BEGIN_NV04(push, SUBC_3D(0x1e98), 1);
252bf215546Sopenharmony_ci      PUSH_DATA (push, 0x01000000);
253bf215546Sopenharmony_ci      return;
254bf215546Sopenharmony_ci   }
255bf215546Sopenharmony_ci
256bf215546Sopenharmony_ci   if (mode == PIPE_RENDER_COND_WAIT ||
257bf215546Sopenharmony_ci       mode == PIPE_RENDER_COND_BY_REGION_WAIT) {
258bf215546Sopenharmony_ci      BEGIN_NV04(push, SUBC_3D(0x0110), 1);
259bf215546Sopenharmony_ci      PUSH_DATA (push, 0);
260bf215546Sopenharmony_ci   }
261bf215546Sopenharmony_ci
262bf215546Sopenharmony_ci   BEGIN_NV04(push, SUBC_3D(0x1e98), 1);
263bf215546Sopenharmony_ci   PUSH_DATA (push, 0x02000000 | q->qo[1]->hw->start);
264bf215546Sopenharmony_ci}
265bf215546Sopenharmony_ci
266bf215546Sopenharmony_cistatic void
267bf215546Sopenharmony_cinv30_set_active_query_state(struct pipe_context *pipe, bool enable)
268bf215546Sopenharmony_ci{
269bf215546Sopenharmony_ci}
270bf215546Sopenharmony_ci
271bf215546Sopenharmony_civoid
272bf215546Sopenharmony_cinv30_query_init(struct pipe_context *pipe)
273bf215546Sopenharmony_ci{
274bf215546Sopenharmony_ci   struct nouveau_object *eng3d = nv30_context(pipe)->screen->eng3d;
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_ci   pipe->create_query = nv30_query_create;
277bf215546Sopenharmony_ci   pipe->destroy_query = nv30_query_destroy;
278bf215546Sopenharmony_ci   pipe->begin_query = nv30_query_begin;
279bf215546Sopenharmony_ci   pipe->end_query = nv30_query_end;
280bf215546Sopenharmony_ci   pipe->get_query_result = nv30_query_result;
281bf215546Sopenharmony_ci   pipe->set_active_query_state = nv30_set_active_query_state;
282bf215546Sopenharmony_ci   if (eng3d->oclass >= NV40_3D_CLASS)
283bf215546Sopenharmony_ci      pipe->render_condition = nv40_query_render_condition;
284bf215546Sopenharmony_ci}
285