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 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, unsigned index) 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 case PIPE_QUERY_OCCLUSION_PREDICATE: 124 q->enable = NV30_3D_QUERY_ENABLE; 125 q->report = 1; 126 break; 127 case NV30_QUERY_ZCULL_0: 128 case NV30_QUERY_ZCULL_1: 129 case NV30_QUERY_ZCULL_2: 130 case NV30_QUERY_ZCULL_3: 131 q->enable = 0x1804; 132 q->report = 2 + (q->type - NV30_QUERY_ZCULL_0); 133 break; 134 default: 135 FREE(q); 136 return NULL; 137 } 138 139 return (struct pipe_query *)q; 140 } 141 142 static void 143 nv30_query_destroy(struct pipe_context *pipe, struct pipe_query *pq) 144 { 145 FREE(pq); 146 } 147 148 static boolean 149 nv30_query_begin(struct pipe_context *pipe, struct pipe_query *pq) 150 { 151 struct nv30_context *nv30 = nv30_context(pipe); 152 struct nv30_query *q = nv30_query(pq); 153 struct nouveau_pushbuf *push = nv30->base.pushbuf; 154 155 switch (q->type) { 156 case PIPE_QUERY_TIME_ELAPSED: 157 q->qo[0] = nv30_query_object_new(nv30->screen); 158 if (q->qo[0]) { 159 BEGIN_NV04(push, NV30_3D(QUERY_GET), 1); 160 PUSH_DATA (push, (q->report << 24) | q->qo[0]->hw->start); 161 } 162 break; 163 case PIPE_QUERY_TIMESTAMP: 164 return true; 165 default: 166 BEGIN_NV04(push, NV30_3D(QUERY_RESET), 1); 167 PUSH_DATA (push, q->report); 168 break; 169 } 170 171 if (q->enable) { 172 BEGIN_NV04(push, SUBC_3D(q->enable), 1); 173 PUSH_DATA (push, 1); 174 } 175 return true; 176 } 177 178 static bool 179 nv30_query_end(struct pipe_context *pipe, struct pipe_query *pq) 180 { 181 struct nv30_context *nv30 = nv30_context(pipe); 182 struct nv30_screen *screen = nv30->screen; 183 struct nv30_query *q = nv30_query(pq); 184 struct nouveau_pushbuf *push = nv30->base.pushbuf; 185 186 q->qo[1] = nv30_query_object_new(screen); 187 if (q->qo[1]) { 188 BEGIN_NV04(push, NV30_3D(QUERY_GET), 1); 189 PUSH_DATA (push, (q->report << 24) | q->qo[1]->hw->start); 190 } 191 192 if (q->enable) { 193 BEGIN_NV04(push, SUBC_3D(q->enable), 1); 194 PUSH_DATA (push, 0); 195 } 196 PUSH_KICK (push); 197 return true; 198 } 199 200 static boolean 201 nv30_query_result(struct pipe_context *pipe, struct pipe_query *pq, 202 boolean wait, union pipe_query_result *result) 203 { 204 struct nv30_screen *screen = nv30_screen(pipe->screen); 205 struct nv30_query *q = nv30_query(pq); 206 volatile uint32_t *ntfy0 = nv30_ntfy(screen, q->qo[0]); 207 volatile uint32_t *ntfy1 = nv30_ntfy(screen, q->qo[1]); 208 209 if (ntfy1) { 210 while (ntfy1[3] & 0xff000000) { 211 if (!wait) 212 return false; 213 } 214 215 switch (q->type) { 216 case PIPE_QUERY_TIMESTAMP: 217 q->result = *(uint64_t *)&ntfy1[0]; 218 break; 219 case PIPE_QUERY_TIME_ELAPSED: 220 q->result = *(uint64_t *)&ntfy1[0] - *(uint64_t *)&ntfy0[0]; 221 break; 222 default: 223 q->result = ntfy1[2]; 224 break; 225 } 226 227 nv30_query_object_del(screen, &q->qo[0]); 228 nv30_query_object_del(screen, &q->qo[1]); 229 } 230 231 if (q->type == PIPE_QUERY_OCCLUSION_PREDICATE) 232 result->b = !!q->result; 233 else 234 result->u64 = q->result; 235 return true; 236 } 237 238 static void 239 nv40_query_render_condition(struct pipe_context *pipe, 240 struct pipe_query *pq, 241 boolean condition, uint 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 268 nv30_set_active_query_state(struct pipe_context *pipe, boolean enable) 269 { 270 } 271 272 void 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