Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 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 "nouveau/nv_object.xml.h"
27
#include "nv30-40_3d.xml.h"
28
#include "nv30_screen.h"
29
#include "nv30_context.h"
30
 
31
#define LIST_FIRST_ENTRY(__type, __item, __field) \
32
   LIST_ENTRY(__type, (__item)->next, __field)
33
 
34
struct nv30_query_object {
35
   struct list_head list;
36
   struct nouveau_heap *hw;
37
};
38
 
39
static volatile void *
40
nv30_ntfy(struct nv30_screen *screen, struct nv30_query_object *qo)
41
{
42
   struct nv04_notify *query = screen->query->data;
43
   struct nouveau_bo *notify = screen->notify;
44
   volatile void *ntfy = NULL;
45
 
46
   if (qo && qo->hw)
47
      ntfy = (char *)notify->map + query->offset + qo->hw->start;
48
 
49
   return ntfy;
50
}
51
 
52
static void
53
nv30_query_object_del(struct nv30_screen *screen, struct nv30_query_object **po)
54
{
55
   struct nv30_query_object *qo = *po; *po = NULL;
56
   if (qo) {
57
      volatile uint32_t *ntfy = nv30_ntfy(screen, qo);
58
      while (ntfy[3] & 0xff000000) {
59
      }
60
      nouveau_heap_free(&qo->hw);
61
      LIST_DEL(&qo->list);
62
      FREE(qo);
63
   }
64
}
65
 
66
static struct nv30_query_object *
67
nv30_query_object_new(struct nv30_screen *screen)
68
{
69
   struct nv30_query_object *oq, *qo = CALLOC_STRUCT(nv30_query_object);
70
   volatile uint32_t *ntfy;
71
 
72
   if (!qo)
73
      return NULL;
74
 
75
   /* allocate a new hw query object, if no hw objects left we need to
76
    * spin waiting for one to become free
77
    */
78
   while (nouveau_heap_alloc(screen->query_heap, 32, NULL, &qo->hw)) {
79
      oq = LIST_FIRST_ENTRY(struct nv30_query_object, &screen->queries, list);
80
      nv30_query_object_del(screen, &oq);
81
   }
82
 
83
   LIST_ADDTAIL(&qo->list, &screen->queries);
84
 
85
   ntfy = nv30_ntfy(screen, qo);
86
   ntfy[0] = 0x00000000;
87
   ntfy[1] = 0x00000000;
88
   ntfy[2] = 0x00000000;
89
   ntfy[3] = 0x01000000;
90
   return qo;
91
}
92
 
93
struct nv30_query {
94
   struct nv30_query_object *qo[2];
95
   unsigned type;
96
   uint32_t report;
97
   uint32_t enable;
98
   uint64_t result;
99
};
100
 
101
static INLINE struct nv30_query *
102
nv30_query(struct pipe_query *pipe)
103
{
104
   return (struct nv30_query *)pipe;
105
}
106
 
107
static struct pipe_query *
108
nv30_query_create(struct pipe_context *pipe, unsigned type)
109
{
110
   struct nv30_query *q = CALLOC_STRUCT(nv30_query);
111
   if (!q)
112
      return NULL;
113
 
114
   q->type = type;
115
 
116
   switch (q->type) {
117
   case PIPE_QUERY_TIMESTAMP:
118
   case PIPE_QUERY_TIME_ELAPSED:
119
      q->enable = 0x0000;
120
      q->report = 1;
121
      break;
122
   case PIPE_QUERY_OCCLUSION_COUNTER:
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
142
nv30_query_destroy(struct pipe_context *pipe, struct pipe_query *pq)
143
{
144
   FREE(pq);
145
}
146
 
147
static void
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;
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
}
175
 
176
static void
177
nv30_query_end(struct pipe_context *pipe, struct pipe_query *pq)
178
{
179
   struct nv30_context *nv30 = nv30_context(pipe);
180
   struct nv30_screen *screen = nv30->screen;
181
   struct nv30_query *q = nv30_query(pq);
182
   struct nouveau_pushbuf *push = nv30->base.pushbuf;
183
 
184
   q->qo[1] = nv30_query_object_new(screen);
185
   if (q->qo[1]) {
186
      BEGIN_NV04(push, NV30_3D(QUERY_GET), 1);
187
      PUSH_DATA (push, (q->report << 24) | q->qo[1]->hw->start);
188
   }
189
 
190
   if (q->enable) {
191
      BEGIN_NV04(push, SUBC_3D(q->enable), 1);
192
      PUSH_DATA (push, 0);
193
   }
194
   PUSH_KICK (push);
195
}
196
 
197
static boolean
198
nv30_query_result(struct pipe_context *pipe, struct pipe_query *pq,
199
                  boolean wait, union pipe_query_result *result)
200
{
201
   struct nv30_screen *screen = nv30_screen(pipe->screen);
202
   struct nv30_query *q = nv30_query(pq);
203
   volatile uint32_t *ntfy0 = nv30_ntfy(screen, q->qo[0]);
204
   volatile uint32_t *ntfy1 = nv30_ntfy(screen, q->qo[1]);
205
   uint64_t *res64 = &result->u64;
206
 
207
   if (ntfy1) {
208
      while (ntfy1[3] & 0xff000000) {
209
         if (!wait)
210
            return FALSE;
211
      }
212
 
213
      switch (q->type) {
214
      case PIPE_QUERY_TIMESTAMP:
215
         q->result = *(uint64_t *)&ntfy1[0];
216
         break;
217
      case PIPE_QUERY_TIME_ELAPSED:
218
         q->result = *(uint64_t *)&ntfy1[0] - *(uint64_t *)&ntfy0[0];
219
         break;
220
      default:
221
         q->result = ntfy1[2];
222
         break;
223
      }
224
 
225
      nv30_query_object_del(screen, &q->qo[0]);
226
      nv30_query_object_del(screen, &q->qo[1]);
227
   }
228
 
229
   *res64 = q->result;
230
   return TRUE;
231
}
232
 
233
static void
234
nv40_query_render_condition(struct pipe_context *pipe,
235
                            struct pipe_query *pq,
236
                            boolean condition, uint mode)
237
{
238
   struct nv30_context *nv30 = nv30_context(pipe);
239
   struct nv30_query *q = nv30_query(pq);
240
   struct nouveau_pushbuf *push = nv30->base.pushbuf;
241
 
242
   nv30->render_cond_query = pq;
243
   nv30->render_cond_mode = mode;
244
   nv30->render_cond_cond = condition;
245
 
246
   if (!pq) {
247
      BEGIN_NV04(push, SUBC_3D(0x1e98), 1);
248
      PUSH_DATA (push, 0x01000000);
249
      return;
250
   }
251
 
252
   if (mode == PIPE_RENDER_COND_WAIT ||
253
       mode == PIPE_RENDER_COND_BY_REGION_WAIT) {
254
      BEGIN_NV04(push, SUBC_3D(0x0110), 1);
255
      PUSH_DATA (push, 0);
256
   }
257
 
258
   BEGIN_NV04(push, SUBC_3D(0x1e98), 1);
259
   PUSH_DATA (push, 0x02000000 | q->qo[1]->hw->start);
260
}
261
 
262
void
263
nv30_query_init(struct pipe_context *pipe)
264
{
265
   struct nouveau_object *eng3d = nv30_context(pipe)->screen->eng3d;
266
 
267
   pipe->create_query = nv30_query_create;
268
   pipe->destroy_query = nv30_query_destroy;
269
   pipe->begin_query = nv30_query_begin;
270
   pipe->end_query = nv30_query_end;
271
   pipe->get_query_result = nv30_query_result;
272
   if (eng3d->oclass >= NV40_3D_CLASS)
273
      pipe->render_condition = nv40_query_render_condition;
274
}