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 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 125 q->enable = NV30_3D_QUERY_ENABLE; 126 q->report = 1; 127 break; 128 case NV30_QUERY_ZCULL_0: 129 case NV30_QUERY_ZCULL_1: 130 case NV30_QUERY_ZCULL_2: 131 case NV30_QUERY_ZCULL_3: 132 q->enable = 0x1804; 133 q->report = 2 + (q->type - NV30_QUERY_ZCULL_0); 134 break; 135 default: 136 FREE(q); 137 return NULL; 138 } 139 140 return (struct pipe_query *)q; 141 } 142 143 static void 144 nv30_query_destroy(struct pipe_context *pipe, struct pipe_query *pq) 145 { 146 FREE(pq); 147 } 148 149 static boolean 150 nv30_query_begin(struct pipe_context *pipe, struct pipe_query *pq) 151 { 152 struct nv30_context *nv30 = nv30_context(pipe); 153 struct nv30_query *q = nv30_query(pq); 154 struct nouveau_pushbuf *push = nv30->base.pushbuf; 155 156 switch (q->type) { 157 case PIPE_QUERY_TIME_ELAPSED: 158 q->qo[0] = nv30_query_object_new(nv30->screen); 159 if (q->qo[0]) { 160 BEGIN_NV04(push, NV30_3D(QUERY_GET), 1); 161 PUSH_DATA (push, (q->report << 24) | q->qo[0]->hw->start); 162 } 163 break; 164 case PIPE_QUERY_TIMESTAMP: 165 return true; 166 default: 167 BEGIN_NV04(push, NV30_3D(QUERY_RESET), 1); 168 PUSH_DATA (push, q->report); 169 break; 170 } 171 172 if (q->enable) { 173 BEGIN_NV04(push, SUBC_3D(q->enable), 1); 174 PUSH_DATA (push, 1); 175 } 176 return true; 177 } 178 179 static bool 180 nv30_query_end(struct pipe_context *pipe, struct pipe_query *pq) 181 { 182 struct nv30_context *nv30 = nv30_context(pipe); 183 struct nv30_screen *screen = nv30->screen; 184 struct nv30_query *q = nv30_query(pq); 185 struct nouveau_pushbuf *push = nv30->base.pushbuf; 186 187 q->qo[1] = nv30_query_object_new(screen); 188 if (q->qo[1]) { 189 BEGIN_NV04(push, NV30_3D(QUERY_GET), 1); 190 PUSH_DATA (push, (q->report << 24) | q->qo[1]->hw->start); 191 } 192 193 if (q->enable) { 194 BEGIN_NV04(push, SUBC_3D(q->enable), 1); 195 PUSH_DATA (push, 0); 196 } 197 PUSH_KICK (push); 198 return true; 199 } 200 201 static boolean 202 nv30_query_result(struct pipe_context *pipe, struct pipe_query *pq, 203 boolean wait, union pipe_query_result *result) 204 { 205 struct nv30_screen *screen = nv30_screen(pipe->screen); 206 struct nv30_query *q = nv30_query(pq); 207 volatile uint32_t *ntfy0 = nv30_ntfy(screen, q->qo[0]); 208 volatile uint32_t *ntfy1 = nv30_ntfy(screen, q->qo[1]); 209 210 if (ntfy1) { 211 while (ntfy1[3] & 0xff000000) { 212 if (!wait) 213 return false; 214 } 215 216 switch (q->type) { 217 case PIPE_QUERY_TIMESTAMP: 218 q->result = *(uint64_t *)&ntfy1[0]; 219 break; 220 case PIPE_QUERY_TIME_ELAPSED: 221 q->result = *(uint64_t *)&ntfy1[0] - *(uint64_t *)&ntfy0[0]; 222 break; 223 default: 224 q->result = ntfy1[2]; 225 break; 226 } 227 228 nv30_query_object_del(screen, &q->qo[0]); 229 nv30_query_object_del(screen, &q->qo[1]); 230 } 231 232 if (q->type == PIPE_QUERY_OCCLUSION_PREDICATE || 233 q->type == PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE) 234 result->b = !!q->result; 235 else 236 result->u64 = q->result; 237 return true; 238 } 239 240 static void 241 nv40_query_render_condition(struct pipe_context *pipe, 242 struct pipe_query *pq, 243 boolean condition, enum pipe_render_cond_flag mode) 244 { 245 struct nv30_context *nv30 = nv30_context(pipe); 246 struct nv30_query *q = nv30_query(pq); 247 struct nouveau_pushbuf *push = nv30->base.pushbuf; 248 249 nv30->render_cond_query = pq; 250 nv30->render_cond_mode = mode; 251 nv30->render_cond_cond = condition; 252 253 if (!pq) { 254 BEGIN_NV04(push, SUBC_3D(0x1e98), 1); 255 PUSH_DATA (push, 0x01000000); 256 return; 257 } 258 259 if (mode == PIPE_RENDER_COND_WAIT || 260 mode == PIPE_RENDER_COND_BY_REGION_WAIT) { 261 BEGIN_NV04(push, SUBC_3D(0x0110), 1); 262 PUSH_DATA (push, 0); 263 } 264 265 BEGIN_NV04(push, SUBC_3D(0x1e98), 1); 266 PUSH_DATA (push, 0x02000000 | q->qo[1]->hw->start); 267 } 268 269 static void 270 nv30_set_active_query_state(struct pipe_context *pipe, boolean enable) 271 { 272 } 273 274 void 275 nv30_query_init(struct pipe_context *pipe) 276 { 277 struct nouveau_object *eng3d = nv30_context(pipe)->screen->eng3d; 278 279 pipe->create_query = nv30_query_create; 280 pipe->destroy_query = nv30_query_destroy; 281 pipe->begin_query = nv30_query_begin; 282 pipe->end_query = nv30_query_end; 283 pipe->get_query_result = nv30_query_result; 284 pipe->set_active_query_state = nv30_set_active_query_state; 285 if (eng3d->oclass >= NV40_3D_CLASS) 286 pipe->render_condition = nv40_query_render_condition; 287 } 288