1 /************************************************************************** 2 * 3 * Copyright 2007 VMware, Inc. 4 * Copyright 2010 VMware, Inc. 5 * All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, sub license, and/or sell copies of the Software, and to 12 * permit persons to whom the Software is furnished to do so, subject to 13 * the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the 16 * next paragraph) shall be included in all copies or substantial portions 17 * of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22 * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR 23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 **************************************************************************/ 28 29 /* Authors: 30 * Keith Whitwell, Qicheng Christopher Li, Brian Paul 31 */ 32 33 #include "draw/draw_context.h" 34 #include "pipe/p_defines.h" 35 #include "util/u_memory.h" 36 #include "util/os_time.h" 37 #include "lp_context.h" 38 #include "lp_flush.h" 39 #include "lp_fence.h" 40 #include "lp_query.h" 41 #include "lp_screen.h" 42 #include "lp_state.h" 43 #include "lp_rast.h" 44 45 46 static struct llvmpipe_query *llvmpipe_query( struct pipe_query *p ) 47 { 48 return (struct llvmpipe_query *)p; 49 } 50 51 static struct pipe_query * 52 llvmpipe_create_query(struct pipe_context *pipe, 53 unsigned type, 54 unsigned index) 55 { 56 struct llvmpipe_query *pq; 57 58 assert(type < PIPE_QUERY_TYPES); 59 60 pq = CALLOC_STRUCT( llvmpipe_query ); 61 62 if (pq) { 63 pq->type = type; 64 } 65 66 return (struct pipe_query *) pq; 67 } 68 69 70 static void 71 llvmpipe_destroy_query(struct pipe_context *pipe, struct pipe_query *q) 72 { 73 struct llvmpipe_query *pq = llvmpipe_query(q); 74 75 /* Ideally we would refcount queries & not get destroyed until the 76 * last scene had finished with us. 77 */ 78 if (pq->fence) { 79 if (!lp_fence_issued(pq->fence)) 80 llvmpipe_flush(pipe, NULL, __FUNCTION__); 81 82 if (!lp_fence_signalled(pq->fence)) 83 lp_fence_wait(pq->fence); 84 85 lp_fence_reference(&pq->fence, NULL); 86 } 87 88 FREE(pq); 89 } 90 91 92 static boolean 93 llvmpipe_get_query_result(struct pipe_context *pipe, 94 struct pipe_query *q, 95 boolean wait, 96 union pipe_query_result *vresult) 97 { 98 struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen); 99 unsigned num_threads = MAX2(1, screen->num_threads); 100 struct llvmpipe_query *pq = llvmpipe_query(q); 101 uint64_t *result = (uint64_t *)vresult; 102 int i; 103 104 if (pq->fence) { 105 /* only have a fence if there was a scene */ 106 if (!lp_fence_signalled(pq->fence)) { 107 if (!lp_fence_issued(pq->fence)) 108 llvmpipe_flush(pipe, NULL, __FUNCTION__); 109 110 if (!wait) 111 return FALSE; 112 113 lp_fence_wait(pq->fence); 114 } 115 } 116 117 /* Sum the results from each of the threads: 118 */ 119 *result = 0; 120 121 switch (pq->type) { 122 case PIPE_QUERY_OCCLUSION_COUNTER: 123 for (i = 0; i < num_threads; i++) { 124 *result += pq->end[i]; 125 } 126 break; 127 case PIPE_QUERY_OCCLUSION_PREDICATE: 128 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 129 for (i = 0; i < num_threads; i++) { 130 /* safer (still not guaranteed) when there's an overflow */ 131 vresult->b = vresult->b || pq->end[i]; 132 } 133 break; 134 case PIPE_QUERY_TIMESTAMP: 135 for (i = 0; i < num_threads; i++) { 136 if (pq->end[i] > *result) { 137 *result = pq->end[i]; 138 } 139 } 140 break; 141 case PIPE_QUERY_TIMESTAMP_DISJOINT: { 142 struct pipe_query_data_timestamp_disjoint *td = 143 (struct pipe_query_data_timestamp_disjoint *)vresult; 144 /* os_get_time_nano return nanoseconds */ 145 td->frequency = UINT64_C(1000000000); 146 td->disjoint = FALSE; 147 } 148 break; 149 case PIPE_QUERY_GPU_FINISHED: 150 vresult->b = TRUE; 151 break; 152 case PIPE_QUERY_PRIMITIVES_GENERATED: 153 *result = pq->num_primitives_generated; 154 break; 155 case PIPE_QUERY_PRIMITIVES_EMITTED: 156 *result = pq->num_primitives_written; 157 break; 158 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: 159 case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE: 160 vresult->b = pq->num_primitives_generated > pq->num_primitives_written; 161 break; 162 case PIPE_QUERY_SO_STATISTICS: { 163 struct pipe_query_data_so_statistics *stats = 164 (struct pipe_query_data_so_statistics *)vresult; 165 stats->num_primitives_written = pq->num_primitives_written; 166 stats->primitives_storage_needed = pq->num_primitives_generated; 167 } 168 break; 169 case PIPE_QUERY_PIPELINE_STATISTICS: { 170 struct pipe_query_data_pipeline_statistics *stats = 171 (struct pipe_query_data_pipeline_statistics *)vresult; 172 /* only ps_invocations come from binned query */ 173 for (i = 0; i < num_threads; i++) { 174 pq->stats.ps_invocations += pq->end[i]; 175 } 176 pq->stats.ps_invocations *= LP_RASTER_BLOCK_SIZE * LP_RASTER_BLOCK_SIZE; 177 *stats = pq->stats; 178 } 179 break; 180 default: 181 assert(0); 182 break; 183 } 184 185 return TRUE; 186 } 187 188 189 static boolean 190 llvmpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q) 191 { 192 struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe ); 193 struct llvmpipe_query *pq = llvmpipe_query(q); 194 195 /* Check if the query is already in the scene. If so, we need to 196 * flush the scene now. Real apps shouldn't re-use a query in a 197 * frame of rendering. 198 */ 199 if (pq->fence && !lp_fence_issued(pq->fence)) { 200 llvmpipe_finish(pipe, __FUNCTION__); 201 } 202 203 204 memset(pq->start, 0, sizeof(pq->start)); 205 memset(pq->end, 0, sizeof(pq->end)); 206 lp_setup_begin_query(llvmpipe->setup, pq); 207 208 switch (pq->type) { 209 case PIPE_QUERY_PRIMITIVES_EMITTED: 210 pq->num_primitives_written = llvmpipe->so_stats.num_primitives_written; 211 break; 212 case PIPE_QUERY_PRIMITIVES_GENERATED: 213 pq->num_primitives_generated = llvmpipe->so_stats.primitives_storage_needed; 214 break; 215 case PIPE_QUERY_SO_STATISTICS: 216 pq->num_primitives_written = llvmpipe->so_stats.num_primitives_written; 217 pq->num_primitives_generated = llvmpipe->so_stats.primitives_storage_needed; 218 break; 219 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: 220 case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE: 221 pq->num_primitives_written = llvmpipe->so_stats.num_primitives_written; 222 pq->num_primitives_generated = llvmpipe->so_stats.primitives_storage_needed; 223 break; 224 case PIPE_QUERY_PIPELINE_STATISTICS: 225 /* reset our cache */ 226 if (llvmpipe->active_statistics_queries == 0) { 227 memset(&llvmpipe->pipeline_statistics, 0, 228 sizeof(llvmpipe->pipeline_statistics)); 229 } 230 memcpy(&pq->stats, &llvmpipe->pipeline_statistics, sizeof(pq->stats)); 231 llvmpipe->active_statistics_queries++; 232 break; 233 case PIPE_QUERY_OCCLUSION_COUNTER: 234 case PIPE_QUERY_OCCLUSION_PREDICATE: 235 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 236 llvmpipe->active_occlusion_queries++; 237 llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY; 238 break; 239 default: 240 break; 241 } 242 return true; 243 } 244 245 246 static bool 247 llvmpipe_end_query(struct pipe_context *pipe, struct pipe_query *q) 248 { 249 struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe ); 250 struct llvmpipe_query *pq = llvmpipe_query(q); 251 252 lp_setup_end_query(llvmpipe->setup, pq); 253 254 switch (pq->type) { 255 256 case PIPE_QUERY_PRIMITIVES_EMITTED: 257 pq->num_primitives_written = 258 llvmpipe->so_stats.num_primitives_written - pq->num_primitives_written; 259 break; 260 case PIPE_QUERY_PRIMITIVES_GENERATED: 261 pq->num_primitives_generated = 262 llvmpipe->so_stats.primitives_storage_needed - pq->num_primitives_generated; 263 break; 264 case PIPE_QUERY_SO_STATISTICS: 265 pq->num_primitives_written = 266 llvmpipe->so_stats.num_primitives_written - pq->num_primitives_written; 267 pq->num_primitives_generated = 268 llvmpipe->so_stats.primitives_storage_needed - pq->num_primitives_generated; 269 break; 270 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: 271 case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE: 272 pq->num_primitives_written = 273 llvmpipe->so_stats.num_primitives_written - pq->num_primitives_written; 274 pq->num_primitives_generated = 275 llvmpipe->so_stats.primitives_storage_needed - pq->num_primitives_generated; 276 break; 277 case PIPE_QUERY_PIPELINE_STATISTICS: 278 pq->stats.ia_vertices = 279 llvmpipe->pipeline_statistics.ia_vertices - pq->stats.ia_vertices; 280 pq->stats.ia_primitives = 281 llvmpipe->pipeline_statistics.ia_primitives - pq->stats.ia_primitives; 282 pq->stats.vs_invocations = 283 llvmpipe->pipeline_statistics.vs_invocations - pq->stats.vs_invocations; 284 pq->stats.gs_invocations = 285 llvmpipe->pipeline_statistics.gs_invocations - pq->stats.gs_invocations; 286 pq->stats.gs_primitives = 287 llvmpipe->pipeline_statistics.gs_primitives - pq->stats.gs_primitives; 288 pq->stats.c_invocations = 289 llvmpipe->pipeline_statistics.c_invocations - pq->stats.c_invocations; 290 pq->stats.c_primitives = 291 llvmpipe->pipeline_statistics.c_primitives - pq->stats.c_primitives; 292 pq->stats.ps_invocations = 293 llvmpipe->pipeline_statistics.ps_invocations - pq->stats.ps_invocations; 294 295 llvmpipe->active_statistics_queries--; 296 break; 297 case PIPE_QUERY_OCCLUSION_COUNTER: 298 case PIPE_QUERY_OCCLUSION_PREDICATE: 299 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 300 assert(llvmpipe->active_occlusion_queries); 301 llvmpipe->active_occlusion_queries--; 302 llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY; 303 break; 304 default: 305 break; 306 } 307 308 return true; 309 } 310 311 boolean 312 llvmpipe_check_render_cond(struct llvmpipe_context *lp) 313 { 314 struct pipe_context *pipe = &lp->pipe; 315 boolean b, wait; 316 uint64_t result; 317 318 if (!lp->render_cond_query) 319 return TRUE; /* no query predicate, draw normally */ 320 321 wait = (lp->render_cond_mode == PIPE_RENDER_COND_WAIT || 322 lp->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT); 323 324 b = pipe->get_query_result(pipe, lp->render_cond_query, wait, (void*)&result); 325 if (b) 326 return ((!result) == lp->render_cond_cond); 327 else 328 return TRUE; 329 } 330 331 static void 332 llvmpipe_set_active_query_state(struct pipe_context *pipe, boolean enable) 333 { 334 } 335 336 void llvmpipe_init_query_funcs(struct llvmpipe_context *llvmpipe ) 337 { 338 llvmpipe->pipe.create_query = llvmpipe_create_query; 339 llvmpipe->pipe.destroy_query = llvmpipe_destroy_query; 340 llvmpipe->pipe.begin_query = llvmpipe_begin_query; 341 llvmpipe->pipe.end_query = llvmpipe_end_query; 342 llvmpipe->pipe.get_query_result = llvmpipe_get_query_result; 343 llvmpipe->pipe.set_active_query_state = llvmpipe_set_active_query_state; 344 } 345 346 347