1 /* 2 * Copyright 2011 Nouveau Project 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: Christoph Bumiller 23 */ 24 25 #define NVC0_PUSH_EXPLICIT_SPACE_CHECKING 26 27 #include "nvc0/nvc0_context.h" 28 #include "nvc0/nvc0_query.h" 29 #include "nvc0/nvc0_query_sw.h" 30 #include "nvc0/nvc0_query_hw.h" 31 #include "nvc0/nvc0_query_hw_metric.h" 32 #include "nvc0/nvc0_query_hw_sm.h" 33 34 static struct pipe_query * 35 nvc0_create_query(struct pipe_context *pipe, unsigned type, unsigned index) 36 { 37 struct nvc0_context *nvc0 = nvc0_context(pipe); 38 struct nvc0_query *q; 39 40 q = nvc0_sw_create_query(nvc0, type, index); 41 if (!q) 42 q = nvc0_hw_create_query(nvc0, type, index); 43 44 return (struct pipe_query *)q; 45 } 46 47 static void 48 nvc0_destroy_query(struct pipe_context *pipe, struct pipe_query *pq) 49 { 50 struct nvc0_query *q = nvc0_query(pq); 51 q->funcs->destroy_query(nvc0_context(pipe), q); 52 } 53 54 static boolean 55 nvc0_begin_query(struct pipe_context *pipe, struct pipe_query *pq) 56 { 57 struct nvc0_query *q = nvc0_query(pq); 58 return q->funcs->begin_query(nvc0_context(pipe), q); 59 } 60 61 static bool 62 nvc0_end_query(struct pipe_context *pipe, struct pipe_query *pq) 63 { 64 struct nvc0_query *q = nvc0_query(pq); 65 q->funcs->end_query(nvc0_context(pipe), q); 66 return true; 67 } 68 69 static boolean 70 nvc0_get_query_result(struct pipe_context *pipe, struct pipe_query *pq, 71 boolean wait, union pipe_query_result *result) 72 { 73 struct nvc0_query *q = nvc0_query(pq); 74 return q->funcs->get_query_result(nvc0_context(pipe), q, wait, result); 75 } 76 77 static void 78 nvc0_get_query_result_resource(struct pipe_context *pipe, 79 struct pipe_query *pq, 80 boolean wait, 81 enum pipe_query_value_type result_type, 82 int index, 83 struct pipe_resource *resource, 84 unsigned offset) 85 { 86 struct nvc0_query *q = nvc0_query(pq); 87 if (!q->funcs->get_query_result_resource) { 88 assert(!"Unexpected lack of get_query_result_resource"); 89 return; 90 } 91 q->funcs->get_query_result_resource(nvc0_context(pipe), q, wait, result_type, 92 index, resource, offset); 93 } 94 95 static void 96 nvc0_render_condition(struct pipe_context *pipe, 97 struct pipe_query *pq, 98 boolean condition, uint mode) 99 { 100 struct nvc0_context *nvc0 = nvc0_context(pipe); 101 struct nouveau_pushbuf *push = nvc0->base.pushbuf; 102 struct nvc0_query *q = nvc0_query(pq); 103 struct nvc0_hw_query *hq = nvc0_hw_query(q); 104 uint32_t cond; 105 bool wait = 106 mode != PIPE_RENDER_COND_NO_WAIT && 107 mode != PIPE_RENDER_COND_BY_REGION_NO_WAIT; 108 109 if (!pq) { 110 cond = NVC0_3D_COND_MODE_ALWAYS; 111 } 112 else { 113 /* NOTE: comparison of 2 queries only works if both have completed */ 114 switch (q->type) { 115 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: 116 cond = condition ? NVC0_3D_COND_MODE_EQUAL : 117 NVC0_3D_COND_MODE_NOT_EQUAL; 118 wait = true; 119 break; 120 case PIPE_QUERY_OCCLUSION_COUNTER: 121 case PIPE_QUERY_OCCLUSION_PREDICATE: 122 if (likely(!condition)) { 123 if (unlikely(hq->nesting)) 124 cond = wait ? NVC0_3D_COND_MODE_NOT_EQUAL : 125 NVC0_3D_COND_MODE_ALWAYS; 126 else 127 cond = NVC0_3D_COND_MODE_RES_NON_ZERO; 128 } else { 129 cond = wait ? NVC0_3D_COND_MODE_EQUAL : NVC0_3D_COND_MODE_ALWAYS; 130 } 131 break; 132 default: 133 assert(!"render condition query not a predicate"); 134 cond = NVC0_3D_COND_MODE_ALWAYS; 135 break; 136 } 137 } 138 139 nvc0->cond_query = pq; 140 nvc0->cond_cond = condition; 141 nvc0->cond_condmode = cond; 142 nvc0->cond_mode = mode; 143 144 if (!pq) { 145 PUSH_SPACE(push, 2); 146 IMMED_NVC0(push, NVC0_3D(COND_MODE), cond); 147 if (nvc0->screen->compute) 148 IMMED_NVC0(push, NVC0_CP(COND_MODE), cond); 149 return; 150 } 151 152 if (wait) 153 nvc0_hw_query_fifo_wait(nvc0, q); 154 155 PUSH_SPACE(push, 10); 156 PUSH_REFN (push, hq->bo, NOUVEAU_BO_GART | NOUVEAU_BO_RD); 157 BEGIN_NVC0(push, NVC0_3D(COND_ADDRESS_HIGH), 3); 158 PUSH_DATAh(push, hq->bo->offset + hq->offset); 159 PUSH_DATA (push, hq->bo->offset + hq->offset); 160 PUSH_DATA (push, cond); 161 BEGIN_NVC0(push, NVC0_2D(COND_ADDRESS_HIGH), 2); 162 PUSH_DATAh(push, hq->bo->offset + hq->offset); 163 PUSH_DATA (push, hq->bo->offset + hq->offset); 164 if (nvc0->screen->compute) { 165 BEGIN_NVC0(push, NVC0_CP(COND_ADDRESS_HIGH), 3); 166 PUSH_DATAh(push, hq->bo->offset + hq->offset); 167 PUSH_DATA (push, hq->bo->offset + hq->offset); 168 PUSH_DATA (push, cond); 169 } 170 } 171 172 int 173 nvc0_screen_get_driver_query_info(struct pipe_screen *pscreen, 174 unsigned id, 175 struct pipe_driver_query_info *info) 176 { 177 struct nvc0_screen *screen = nvc0_screen(pscreen); 178 int num_sw_queries = 0, num_hw_queries = 0; 179 180 num_sw_queries = nvc0_sw_get_driver_query_info(screen, 0, NULL); 181 num_hw_queries = nvc0_hw_get_driver_query_info(screen, 0, NULL); 182 183 if (!info) 184 return num_sw_queries + num_hw_queries; 185 186 /* Init default values. */ 187 info->name = "this_is_not_the_query_you_are_looking_for"; 188 info->query_type = 0xdeadd01d; 189 info->max_value.u64 = 0; 190 info->type = PIPE_DRIVER_QUERY_TYPE_UINT64; 191 info->group_id = -1; 192 info->flags = 0; 193 194 #ifdef NOUVEAU_ENABLE_DRIVER_STATISTICS 195 if (id < num_sw_queries) 196 return nvc0_sw_get_driver_query_info(screen, id, info); 197 #endif 198 199 return nvc0_hw_get_driver_query_info(screen, id - num_sw_queries, info); 200 } 201 202 int 203 nvc0_screen_get_driver_query_group_info(struct pipe_screen *pscreen, 204 unsigned id, 205 struct pipe_driver_query_group_info *info) 206 { 207 struct nvc0_screen *screen = nvc0_screen(pscreen); 208 int count = 0; 209 210 #ifdef NOUVEAU_ENABLE_DRIVER_STATISTICS 211 count++; 212 #endif 213 214 if (screen->base.drm->version >= 0x01000101) { 215 if (screen->compute) { 216 if (screen->base.class_3d <= GM200_3D_CLASS) { 217 count += 2; 218 } 219 } 220 } 221 222 if (!info) 223 return count; 224 225 if (id == NVC0_HW_SM_QUERY_GROUP) { 226 if (screen->compute) { 227 info->name = "MP counters"; 228 229 /* Expose the maximum number of hardware counters available, although 230 * some queries use more than one counter. Expect failures in that 231 * case but as performance counters are for developers, this should 232 * not have a real impact. */ 233 info->max_active_queries = 8; 234 info->num_queries = nvc0_hw_sm_get_num_queries(screen); 235 return 1; 236 } 237 } else 238 if (id == NVC0_HW_METRIC_QUERY_GROUP) { 239 if (screen->compute) { 240 if (screen->base.class_3d <= GM200_3D_CLASS) { 241 info->name = "Performance metrics"; 242 info->max_active_queries = 4; /* A metric uses at least 2 queries */ 243 info->num_queries = nvc0_hw_metric_get_num_queries(screen); 244 return 1; 245 } 246 } 247 } 248 #ifdef NOUVEAU_ENABLE_DRIVER_STATISTICS 249 else if (id == NVC0_SW_QUERY_DRV_STAT_GROUP) { 250 info->name = "Driver statistics"; 251 info->max_active_queries = NVC0_SW_QUERY_DRV_STAT_COUNT; 252 info->num_queries = NVC0_SW_QUERY_DRV_STAT_COUNT; 253 return 1; 254 } 255 #endif 256 257 /* user asked for info about non-existing query group */ 258 info->name = "this_is_not_the_query_group_you_are_looking_for"; 259 info->max_active_queries = 0; 260 info->num_queries = 0; 261 return 0; 262 } 263 264 static void 265 nvc0_set_active_query_state(struct pipe_context *pipe, boolean enable) 266 { 267 } 268 269 void 270 nvc0_init_query_functions(struct nvc0_context *nvc0) 271 { 272 struct pipe_context *pipe = &nvc0->base.pipe; 273 274 pipe->create_query = nvc0_create_query; 275 pipe->destroy_query = nvc0_destroy_query; 276 pipe->begin_query = nvc0_begin_query; 277 pipe->end_query = nvc0_end_query; 278 pipe->get_query_result = nvc0_get_query_result; 279 pipe->get_query_result_resource = nvc0_get_query_result_resource; 280 pipe->set_active_query_state = nvc0_set_active_query_state; 281 pipe->render_condition = nvc0_render_condition; 282 nvc0->cond_condmode = NVC0_3D_COND_MODE_ALWAYS; 283 } 284