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