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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * 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, uint mode) 236 { 237 struct nv30_context *nv30 = nv30_context(pipe); 238 struct nv30_query *q = nv30_query(pq); 239 struct nouveau_pushbuf *push = nv30->base.pushbuf; 240 241 if (!pq) { 242 BEGIN_NV04(push, SUBC_3D(0x1e98), 1); 243 PUSH_DATA (push, 0x01000000); 244 return; 245 } 246 247 if (mode == PIPE_RENDER_COND_WAIT || 248 mode == PIPE_RENDER_COND_BY_REGION_WAIT) { 249 BEGIN_NV04(push, SUBC_3D(0x0110), 1); 250 PUSH_DATA (push, 0); 251 } 252 253 BEGIN_NV04(push, SUBC_3D(0x1e98), 1); 254 PUSH_DATA (push, 0x02000000 | q->qo[1]->hw->start); 255 } 256 257 void 258 nv30_query_init(struct pipe_context *pipe) 259 { 260 struct nouveau_object *eng3d = nv30_context(pipe)->screen->eng3d; 261 262 pipe->create_query = nv30_query_create; 263 pipe->destroy_query = nv30_query_destroy; 264 pipe->begin_query = nv30_query_begin; 265 pipe->end_query = nv30_query_end; 266 pipe->get_query_result = nv30_query_result; 267 if (eng3d->oclass >= NV40_3D_CLASS) 268 pipe->render_condition = nv40_query_render_condition; 269 } 270