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 46static struct llvmpipe_query *llvmpipe_query( struct pipe_query *p ) 47{ 48 return (struct llvmpipe_query *)p; 49} 50 51static struct pipe_query * 52llvmpipe_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 pq->index = index; 65 } 66 67 return (struct pipe_query *) pq; 68} 69 70 71static void 72llvmpipe_destroy_query(struct pipe_context *pipe, struct pipe_query *q) 73{ 74 struct llvmpipe_query *pq = llvmpipe_query(q); 75 76 /* Ideally we would refcount queries & not get destroyed until the 77 * last scene had finished with us. 78 */ 79 if (pq->fence) { 80 if (!lp_fence_issued(pq->fence)) 81 llvmpipe_flush(pipe, NULL, __FUNCTION__); 82 83 if (!lp_fence_signalled(pq->fence)) 84 lp_fence_wait(pq->fence); 85 86 lp_fence_reference(&pq->fence, NULL); 87 } 88 89 FREE(pq); 90} 91 92 93static bool 94llvmpipe_get_query_result(struct pipe_context *pipe, 95 struct pipe_query *q, 96 bool wait, 97 union pipe_query_result *vresult) 98{ 99 struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen); 100 unsigned num_threads = MAX2(1, screen->num_threads); 101 struct llvmpipe_query *pq = llvmpipe_query(q); 102 uint64_t *result = (uint64_t *)vresult; 103 int i; 104 105 if (pq->fence) { 106 /* only have a fence if there was a scene */ 107 if (!lp_fence_signalled(pq->fence)) { 108 if (!lp_fence_issued(pq->fence)) 109 llvmpipe_flush(pipe, NULL, __FUNCTION__); 110 111 if (!wait) 112 return false; 113 114 lp_fence_wait(pq->fence); 115 } 116 } 117 118 /* Sum the results from each of the threads: 119 */ 120 *result = 0; 121 122 switch (pq->type) { 123 case PIPE_QUERY_OCCLUSION_COUNTER: 124 for (i = 0; i < num_threads; i++) { 125 *result += pq->end[i]; 126 } 127 break; 128 case PIPE_QUERY_OCCLUSION_PREDICATE: 129 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 130 for (i = 0; i < num_threads; i++) { 131 /* safer (still not guaranteed) when there's an overflow */ 132 vresult->b = vresult->b || pq->end[i]; 133 } 134 break; 135 case PIPE_QUERY_TIMESTAMP: 136 for (i = 0; i < num_threads; i++) { 137 if (pq->end[i] > *result) { 138 *result = pq->end[i]; 139 } 140 } 141 break; 142 case PIPE_QUERY_TIME_ELAPSED: { 143 uint64_t start = (uint64_t)-1, end = 0; 144 for (i = 0; i < num_threads; i++) { 145 if (pq->start[i] && pq->start[i] < start) 146 start = pq->start[i]; 147 if (pq->end[i] && pq->end[i] > end) 148 end = pq->end[i]; 149 } 150 *result = end - start; 151 break; 152 } 153 case PIPE_QUERY_TIMESTAMP_DISJOINT: { 154 struct pipe_query_data_timestamp_disjoint *td = 155 (struct pipe_query_data_timestamp_disjoint *)vresult; 156 /* os_get_time_nano return nanoseconds */ 157 td->frequency = UINT64_C(1000000000); 158 td->disjoint = false; 159 } 160 break; 161 case PIPE_QUERY_GPU_FINISHED: 162 vresult->b = true; 163 break; 164 case PIPE_QUERY_PRIMITIVES_GENERATED: 165 *result = pq->num_primitives_generated[0]; 166 break; 167 case PIPE_QUERY_PRIMITIVES_EMITTED: 168 *result = pq->num_primitives_written[0]; 169 break; 170 case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE: 171 vresult->b = false; 172 for (unsigned s = 0; s < PIPE_MAX_VERTEX_STREAMS; s++) 173 vresult->b |= pq->num_primitives_generated[s] > pq->num_primitives_written[s]; 174 break; 175 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: 176 vresult->b = pq->num_primitives_generated[0] > pq->num_primitives_written[0]; 177 break; 178 case PIPE_QUERY_SO_STATISTICS: { 179 struct pipe_query_data_so_statistics *stats = 180 (struct pipe_query_data_so_statistics *)vresult; 181 stats->num_primitives_written = pq->num_primitives_written[0]; 182 stats->primitives_storage_needed = pq->num_primitives_generated[0]; 183 } 184 break; 185 case PIPE_QUERY_PIPELINE_STATISTICS: { 186 struct pipe_query_data_pipeline_statistics *stats = 187 (struct pipe_query_data_pipeline_statistics *)vresult; 188 /* only ps_invocations come from binned query */ 189 for (i = 0; i < num_threads; i++) { 190 pq->stats.ps_invocations += pq->end[i]; 191 } 192 pq->stats.ps_invocations *= LP_RASTER_BLOCK_SIZE * LP_RASTER_BLOCK_SIZE; 193 *stats = pq->stats; 194 } 195 break; 196 default: 197 assert(0); 198 break; 199 } 200 201 return true; 202} 203 204static void 205llvmpipe_get_query_result_resource(struct pipe_context *pipe, 206 struct pipe_query *q, 207 bool wait, 208 enum pipe_query_value_type result_type, 209 int index, 210 struct pipe_resource *resource, 211 unsigned offset) 212{ 213 struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen); 214 unsigned num_threads = MAX2(1, screen->num_threads); 215 struct llvmpipe_query *pq = llvmpipe_query(q); 216 struct llvmpipe_resource *lpr = llvmpipe_resource(resource); 217 bool unsignalled = false; 218 if (pq->fence) { 219 /* only have a fence if there was a scene */ 220 if (!lp_fence_signalled(pq->fence)) { 221 if (!lp_fence_issued(pq->fence)) 222 llvmpipe_flush(pipe, NULL, __FUNCTION__); 223 224 if (wait) 225 lp_fence_wait(pq->fence); 226 } 227 unsignalled = !lp_fence_signalled(pq->fence); 228 } 229 230 231 uint64_t value = 0, value2 = 0; 232 unsigned num_values = 1; 233 if (index == -1) 234 if (unsignalled) 235 value = 0; 236 else 237 value = 1; 238 else { 239 unsigned i; 240 241 switch (pq->type) { 242 case PIPE_QUERY_OCCLUSION_COUNTER: 243 for (i = 0; i < num_threads; i++) { 244 value += pq->end[i]; 245 } 246 break; 247 case PIPE_QUERY_OCCLUSION_PREDICATE: 248 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 249 for (i = 0; i < num_threads; i++) { 250 /* safer (still not guaranteed) when there's an overflow */ 251 value = value || pq->end[i]; 252 } 253 break; 254 case PIPE_QUERY_PRIMITIVES_GENERATED: 255 value = pq->num_primitives_generated[0]; 256 break; 257 case PIPE_QUERY_PRIMITIVES_EMITTED: 258 value = pq->num_primitives_written[0]; 259 break; 260 case PIPE_QUERY_TIMESTAMP: 261 for (i = 0; i < num_threads; i++) { 262 if (pq->end[i] > value) { 263 value = pq->end[i]; 264 } 265 } 266 break; 267 case PIPE_QUERY_TIME_ELAPSED: { 268 uint64_t start = (uint64_t)-1, end = 0; 269 for (i = 0; i < num_threads; i++) { 270 if (pq->start[i] && pq->start[i] < start) 271 start = pq->start[i]; 272 if (pq->end[i] && pq->end[i] > end) 273 end = pq->end[i]; 274 } 275 value = end - start; 276 break; 277 } 278 case PIPE_QUERY_SO_STATISTICS: 279 value = pq->num_primitives_written[0]; 280 value2 = pq->num_primitives_generated[0]; 281 num_values = 2; 282 break; 283 case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE: 284 value = 0; 285 for (unsigned s = 0; s < PIPE_MAX_VERTEX_STREAMS; s++) 286 value |= !!(pq->num_primitives_generated[s] > pq->num_primitives_written[s]); 287 break; 288 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: 289 value = !!(pq->num_primitives_generated[0] > pq->num_primitives_written[0]); 290 break; 291 case PIPE_QUERY_PIPELINE_STATISTICS: 292 switch ((enum pipe_statistics_query_index)index) { 293 case PIPE_STAT_QUERY_IA_VERTICES: 294 value = pq->stats.ia_vertices; 295 break; 296 case PIPE_STAT_QUERY_IA_PRIMITIVES: 297 value = pq->stats.ia_primitives; 298 break; 299 case PIPE_STAT_QUERY_VS_INVOCATIONS: 300 value = pq->stats.vs_invocations; 301 break; 302 case PIPE_STAT_QUERY_GS_INVOCATIONS: 303 value = pq->stats.gs_invocations; 304 break; 305 case PIPE_STAT_QUERY_GS_PRIMITIVES: 306 value = pq->stats.gs_primitives; 307 break; 308 case PIPE_STAT_QUERY_C_INVOCATIONS: 309 value = pq->stats.c_invocations; 310 break; 311 case PIPE_STAT_QUERY_C_PRIMITIVES: 312 value = pq->stats.c_primitives; 313 break; 314 case PIPE_STAT_QUERY_PS_INVOCATIONS: 315 value = 0; 316 for (i = 0; i < num_threads; i++) { 317 value += pq->end[i]; 318 } 319 value *= LP_RASTER_BLOCK_SIZE * LP_RASTER_BLOCK_SIZE; 320 break; 321 case PIPE_STAT_QUERY_HS_INVOCATIONS: 322 value = pq->stats.hs_invocations; 323 break; 324 case PIPE_STAT_QUERY_DS_INVOCATIONS: 325 value = pq->stats.ds_invocations; 326 break; 327 case PIPE_STAT_QUERY_CS_INVOCATIONS: 328 value = pq->stats.cs_invocations; 329 break; 330 } 331 break; 332 default: 333 fprintf(stderr, "Unknown query type %d\n", pq->type); 334 break; 335 } 336 } 337 338 void *dst = (uint8_t *)lpr->data + offset; 339 340 for (unsigned i = 0; i < num_values; i++) { 341 342 if (i == 1) { 343 value = value2; 344 dst = (char *)dst + ((result_type == PIPE_QUERY_TYPE_I64 || 345 result_type == PIPE_QUERY_TYPE_U64) ? 8 : 4); 346 } 347 switch (result_type) { 348 case PIPE_QUERY_TYPE_I32: { 349 int32_t *iptr = (int32_t *)dst; 350 if (value > 0x7fffffff) 351 *iptr = 0x7fffffff; 352 else 353 *iptr = (int32_t)value; 354 break; 355 } 356 case PIPE_QUERY_TYPE_U32: { 357 uint32_t *uptr = (uint32_t *)dst; 358 if (value > 0xffffffff) 359 *uptr = 0xffffffff; 360 else 361 *uptr = (uint32_t)value; 362 break; 363 } 364 case PIPE_QUERY_TYPE_I64: { 365 int64_t *iptr = (int64_t *)dst; 366 *iptr = (int64_t)value; 367 break; 368 } 369 case PIPE_QUERY_TYPE_U64: { 370 uint64_t *uptr = (uint64_t *)dst; 371 *uptr = (uint64_t)value; 372 break; 373 } 374 } 375 } 376} 377 378static bool 379llvmpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q) 380{ 381 struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe ); 382 struct llvmpipe_query *pq = llvmpipe_query(q); 383 384 /* Check if the query is already in the scene. If so, we need to 385 * flush the scene now. Real apps shouldn't re-use a query in a 386 * frame of rendering. 387 */ 388 if (pq->fence && !lp_fence_issued(pq->fence)) { 389 llvmpipe_finish(pipe, __FUNCTION__); 390 } 391 392 393 memset(pq->start, 0, sizeof(pq->start)); 394 memset(pq->end, 0, sizeof(pq->end)); 395 lp_setup_begin_query(llvmpipe->setup, pq); 396 397 switch (pq->type) { 398 case PIPE_QUERY_PRIMITIVES_EMITTED: 399 pq->num_primitives_written[0] = llvmpipe->so_stats[pq->index].num_primitives_written; 400 break; 401 case PIPE_QUERY_PRIMITIVES_GENERATED: 402 pq->num_primitives_generated[0] = llvmpipe->so_stats[pq->index].primitives_storage_needed; 403 llvmpipe->active_primgen_queries++; 404 break; 405 case PIPE_QUERY_SO_STATISTICS: 406 pq->num_primitives_written[0] = llvmpipe->so_stats[pq->index].num_primitives_written; 407 pq->num_primitives_generated[0] = llvmpipe->so_stats[pq->index].primitives_storage_needed; 408 break; 409 case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE: 410 for (unsigned s = 0; s < PIPE_MAX_VERTEX_STREAMS; s++) { 411 pq->num_primitives_written[s] = llvmpipe->so_stats[s].num_primitives_written; 412 pq->num_primitives_generated[s] = llvmpipe->so_stats[s].primitives_storage_needed; 413 } 414 break; 415 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: 416 pq->num_primitives_written[0] = llvmpipe->so_stats[pq->index].num_primitives_written; 417 pq->num_primitives_generated[0] = llvmpipe->so_stats[pq->index].primitives_storage_needed; 418 break; 419 case PIPE_QUERY_PIPELINE_STATISTICS: 420 /* reset our cache */ 421 if (llvmpipe->active_statistics_queries == 0) { 422 memset(&llvmpipe->pipeline_statistics, 0, 423 sizeof(llvmpipe->pipeline_statistics)); 424 } 425 memcpy(&pq->stats, &llvmpipe->pipeline_statistics, sizeof(pq->stats)); 426 llvmpipe->active_statistics_queries++; 427 break; 428 case PIPE_QUERY_OCCLUSION_COUNTER: 429 case PIPE_QUERY_OCCLUSION_PREDICATE: 430 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 431 llvmpipe->active_occlusion_queries++; 432 llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY; 433 break; 434 default: 435 break; 436 } 437 return true; 438} 439 440 441static bool 442llvmpipe_end_query(struct pipe_context *pipe, struct pipe_query *q) 443{ 444 struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe ); 445 struct llvmpipe_query *pq = llvmpipe_query(q); 446 447 lp_setup_end_query(llvmpipe->setup, pq); 448 449 switch (pq->type) { 450 451 case PIPE_QUERY_PRIMITIVES_EMITTED: 452 pq->num_primitives_written[0] = 453 llvmpipe->so_stats[pq->index].num_primitives_written - pq->num_primitives_written[0]; 454 break; 455 case PIPE_QUERY_PRIMITIVES_GENERATED: 456 assert(llvmpipe->active_primgen_queries); 457 llvmpipe->active_primgen_queries--; 458 pq->num_primitives_generated[0] = 459 llvmpipe->so_stats[pq->index].primitives_storage_needed - pq->num_primitives_generated[0]; 460 break; 461 case PIPE_QUERY_SO_STATISTICS: 462 pq->num_primitives_written[0] = 463 llvmpipe->so_stats[pq->index].num_primitives_written - pq->num_primitives_written[0]; 464 pq->num_primitives_generated[0] = 465 llvmpipe->so_stats[pq->index].primitives_storage_needed - pq->num_primitives_generated[0]; 466 break; 467 case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE: 468 for (unsigned s = 0; s < PIPE_MAX_VERTEX_STREAMS; s++) { 469 pq->num_primitives_written[s] = 470 llvmpipe->so_stats[s].num_primitives_written - pq->num_primitives_written[s]; 471 pq->num_primitives_generated[s] = 472 llvmpipe->so_stats[s].primitives_storage_needed - pq->num_primitives_generated[s]; 473 } 474 break; 475 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: 476 pq->num_primitives_written[0] = 477 llvmpipe->so_stats[pq->index].num_primitives_written - pq->num_primitives_written[0]; 478 pq->num_primitives_generated[0] = 479 llvmpipe->so_stats[pq->index].primitives_storage_needed - pq->num_primitives_generated[0]; 480 break; 481 case PIPE_QUERY_PIPELINE_STATISTICS: 482 pq->stats.ia_vertices = 483 llvmpipe->pipeline_statistics.ia_vertices - pq->stats.ia_vertices; 484 pq->stats.ia_primitives = 485 llvmpipe->pipeline_statistics.ia_primitives - pq->stats.ia_primitives; 486 pq->stats.vs_invocations = 487 llvmpipe->pipeline_statistics.vs_invocations - pq->stats.vs_invocations; 488 pq->stats.gs_invocations = 489 llvmpipe->pipeline_statistics.gs_invocations - pq->stats.gs_invocations; 490 pq->stats.gs_primitives = 491 llvmpipe->pipeline_statistics.gs_primitives - pq->stats.gs_primitives; 492 pq->stats.c_invocations = 493 llvmpipe->pipeline_statistics.c_invocations - pq->stats.c_invocations; 494 pq->stats.c_primitives = 495 llvmpipe->pipeline_statistics.c_primitives - pq->stats.c_primitives; 496 pq->stats.ps_invocations = 497 llvmpipe->pipeline_statistics.ps_invocations - pq->stats.ps_invocations; 498 pq->stats.cs_invocations = 499 llvmpipe->pipeline_statistics.cs_invocations - pq->stats.cs_invocations; 500 pq->stats.hs_invocations = 501 llvmpipe->pipeline_statistics.hs_invocations - pq->stats.hs_invocations; 502 pq->stats.ds_invocations = 503 llvmpipe->pipeline_statistics.ds_invocations - pq->stats.ds_invocations; 504 llvmpipe->active_statistics_queries--; 505 break; 506 case PIPE_QUERY_OCCLUSION_COUNTER: 507 case PIPE_QUERY_OCCLUSION_PREDICATE: 508 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 509 assert(llvmpipe->active_occlusion_queries); 510 llvmpipe->active_occlusion_queries--; 511 llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY; 512 break; 513 default: 514 break; 515 } 516 517 return true; 518} 519 520boolean 521llvmpipe_check_render_cond(struct llvmpipe_context *lp) 522{ 523 struct pipe_context *pipe = &lp->pipe; 524 boolean b, wait; 525 uint64_t result; 526 527 if (lp->render_cond_buffer) { 528 uint32_t data = *(uint32_t *)((char *)lp->render_cond_buffer->data + lp->render_cond_offset); 529 return (!data) == lp->render_cond_cond; 530 } 531 if (!lp->render_cond_query) 532 return TRUE; /* no query predicate, draw normally */ 533 534 wait = (lp->render_cond_mode == PIPE_RENDER_COND_WAIT || 535 lp->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT); 536 537 b = pipe->get_query_result(pipe, lp->render_cond_query, wait, (void*)&result); 538 if (b) 539 return ((!result) == lp->render_cond_cond); 540 else 541 return TRUE; 542} 543 544static void 545llvmpipe_set_active_query_state(struct pipe_context *pipe, bool enable) 546{ 547 struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe); 548 549 llvmpipe->queries_disabled = !enable; 550 /* for OQs we need to regenerate the fragment shader */ 551 llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY; 552} 553 554void llvmpipe_init_query_funcs(struct llvmpipe_context *llvmpipe ) 555{ 556 llvmpipe->pipe.create_query = llvmpipe_create_query; 557 llvmpipe->pipe.destroy_query = llvmpipe_destroy_query; 558 llvmpipe->pipe.begin_query = llvmpipe_begin_query; 559 llvmpipe->pipe.end_query = llvmpipe_end_query; 560 llvmpipe->pipe.get_query_result = llvmpipe_get_query_result; 561 llvmpipe->pipe.get_query_result_resource = llvmpipe_get_query_result_resource; 562 llvmpipe->pipe.set_active_query_state = llvmpipe_set_active_query_state; 563} 564 565 566