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 enum pipe_query_flags flags, 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 (flags & PIPE_QUERY_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 /* don't write a value if fence hasn't signalled, 242 and partial isn't set . */ 243 if (unsignalled && !(flags & PIPE_QUERY_PARTIAL)) 244 return; 245 switch (pq->type) { 246 case PIPE_QUERY_OCCLUSION_COUNTER: 247 for (i = 0; i < num_threads; i++) { 248 value += pq->end[i]; 249 } 250 break; 251 case PIPE_QUERY_OCCLUSION_PREDICATE: 252 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 253 for (i = 0; i < num_threads; i++) { 254 /* safer (still not guaranteed) when there's an overflow */ 255 value = value || pq->end[i]; 256 } 257 break; 258 case PIPE_QUERY_PRIMITIVES_GENERATED: 259 value = pq->num_primitives_generated[0]; 260 break; 261 case PIPE_QUERY_PRIMITIVES_EMITTED: 262 value = pq->num_primitives_written[0]; 263 break; 264 case PIPE_QUERY_TIMESTAMP: 265 for (i = 0; i < num_threads; i++) { 266 if (pq->end[i] > value) { 267 value = pq->end[i]; 268 } 269 } 270 break; 271 case PIPE_QUERY_TIME_ELAPSED: { 272 uint64_t start = (uint64_t)-1, end = 0; 273 for (i = 0; i < num_threads; i++) { 274 if (pq->start[i] && pq->start[i] < start) 275 start = pq->start[i]; 276 if (pq->end[i] && pq->end[i] > end) 277 end = pq->end[i]; 278 } 279 value = end - start; 280 break; 281 } 282 case PIPE_QUERY_SO_STATISTICS: 283 value = pq->num_primitives_written[0]; 284 value2 = pq->num_primitives_generated[0]; 285 num_values = 2; 286 break; 287 case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE: 288 value = 0; 289 for (unsigned s = 0; s < PIPE_MAX_VERTEX_STREAMS; s++) 290 value |= !!(pq->num_primitives_generated[s] > pq->num_primitives_written[s]); 291 break; 292 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: 293 value = !!(pq->num_primitives_generated[0] > pq->num_primitives_written[0]); 294 break; 295 case PIPE_QUERY_PIPELINE_STATISTICS: 296 switch ((enum pipe_statistics_query_index)index) { 297 case PIPE_STAT_QUERY_IA_VERTICES: 298 value = pq->stats.ia_vertices; 299 break; 300 case PIPE_STAT_QUERY_IA_PRIMITIVES: 301 value = pq->stats.ia_primitives; 302 break; 303 case PIPE_STAT_QUERY_VS_INVOCATIONS: 304 value = pq->stats.vs_invocations; 305 break; 306 case PIPE_STAT_QUERY_GS_INVOCATIONS: 307 value = pq->stats.gs_invocations; 308 break; 309 case PIPE_STAT_QUERY_GS_PRIMITIVES: 310 value = pq->stats.gs_primitives; 311 break; 312 case PIPE_STAT_QUERY_C_INVOCATIONS: 313 value = pq->stats.c_invocations; 314 break; 315 case PIPE_STAT_QUERY_C_PRIMITIVES: 316 value = pq->stats.c_primitives; 317 break; 318 case PIPE_STAT_QUERY_PS_INVOCATIONS: 319 value = 0; 320 for (i = 0; i < num_threads; i++) { 321 value += pq->end[i]; 322 } 323 value *= LP_RASTER_BLOCK_SIZE * LP_RASTER_BLOCK_SIZE; 324 break; 325 case PIPE_STAT_QUERY_HS_INVOCATIONS: 326 value = pq->stats.hs_invocations; 327 break; 328 case PIPE_STAT_QUERY_DS_INVOCATIONS: 329 value = pq->stats.ds_invocations; 330 break; 331 case PIPE_STAT_QUERY_CS_INVOCATIONS: 332 value = pq->stats.cs_invocations; 333 break; 334 } 335 break; 336 default: 337 fprintf(stderr, "Unknown query type %d\n", pq->type); 338 break; 339 } 340 } 341 342 void *dst = (uint8_t *)lpr->data + offset; 343 344 for (unsigned i = 0; i < num_values; i++) { 345 346 if (i == 1) { 347 value = value2; 348 dst = (char *)dst + ((result_type == PIPE_QUERY_TYPE_I64 || 349 result_type == PIPE_QUERY_TYPE_U64) ? 8 : 4); 350 } 351 switch (result_type) { 352 case PIPE_QUERY_TYPE_I32: { 353 int32_t *iptr = (int32_t *)dst; 354 if (value > 0x7fffffff) 355 *iptr = 0x7fffffff; 356 else 357 *iptr = (int32_t)value; 358 break; 359 } 360 case PIPE_QUERY_TYPE_U32: { 361 uint32_t *uptr = (uint32_t *)dst; 362 if (value > 0xffffffff) 363 *uptr = 0xffffffff; 364 else 365 *uptr = (uint32_t)value; 366 break; 367 } 368 case PIPE_QUERY_TYPE_I64: { 369 int64_t *iptr = (int64_t *)dst; 370 *iptr = (int64_t)value; 371 break; 372 } 373 case PIPE_QUERY_TYPE_U64: { 374 uint64_t *uptr = (uint64_t *)dst; 375 *uptr = (uint64_t)value; 376 break; 377 } 378 } 379 } 380} 381 382static bool 383llvmpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q) 384{ 385 struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe ); 386 struct llvmpipe_query *pq = llvmpipe_query(q); 387 388 /* Check if the query is already in the scene. If so, we need to 389 * flush the scene now. Real apps shouldn't re-use a query in a 390 * frame of rendering. 391 */ 392 if (pq->fence && !lp_fence_issued(pq->fence)) { 393 llvmpipe_finish(pipe, __FUNCTION__); 394 } 395 396 397 memset(pq->start, 0, sizeof(pq->start)); 398 memset(pq->end, 0, sizeof(pq->end)); 399 lp_setup_begin_query(llvmpipe->setup, pq); 400 401 switch (pq->type) { 402 case PIPE_QUERY_PRIMITIVES_EMITTED: 403 pq->num_primitives_written[0] = llvmpipe->so_stats[pq->index].num_primitives_written; 404 break; 405 case PIPE_QUERY_PRIMITIVES_GENERATED: 406 pq->num_primitives_generated[0] = llvmpipe->so_stats[pq->index].primitives_storage_needed; 407 llvmpipe->active_primgen_queries++; 408 break; 409 case PIPE_QUERY_SO_STATISTICS: 410 pq->num_primitives_written[0] = llvmpipe->so_stats[pq->index].num_primitives_written; 411 pq->num_primitives_generated[0] = llvmpipe->so_stats[pq->index].primitives_storage_needed; 412 break; 413 case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE: 414 for (unsigned s = 0; s < PIPE_MAX_VERTEX_STREAMS; s++) { 415 pq->num_primitives_written[s] = llvmpipe->so_stats[s].num_primitives_written; 416 pq->num_primitives_generated[s] = llvmpipe->so_stats[s].primitives_storage_needed; 417 } 418 break; 419 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: 420 pq->num_primitives_written[0] = llvmpipe->so_stats[pq->index].num_primitives_written; 421 pq->num_primitives_generated[0] = llvmpipe->so_stats[pq->index].primitives_storage_needed; 422 break; 423 case PIPE_QUERY_PIPELINE_STATISTICS: 424 /* reset our cache */ 425 if (llvmpipe->active_statistics_queries == 0) { 426 memset(&llvmpipe->pipeline_statistics, 0, 427 sizeof(llvmpipe->pipeline_statistics)); 428 } 429 memcpy(&pq->stats, &llvmpipe->pipeline_statistics, sizeof(pq->stats)); 430 llvmpipe->active_statistics_queries++; 431 break; 432 case PIPE_QUERY_OCCLUSION_COUNTER: 433 case PIPE_QUERY_OCCLUSION_PREDICATE: 434 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 435 llvmpipe->active_occlusion_queries++; 436 llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY; 437 break; 438 default: 439 break; 440 } 441 return true; 442} 443 444 445static bool 446llvmpipe_end_query(struct pipe_context *pipe, struct pipe_query *q) 447{ 448 struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe ); 449 struct llvmpipe_query *pq = llvmpipe_query(q); 450 451 lp_setup_end_query(llvmpipe->setup, pq); 452 453 switch (pq->type) { 454 455 case PIPE_QUERY_PRIMITIVES_EMITTED: 456 pq->num_primitives_written[0] = 457 llvmpipe->so_stats[pq->index].num_primitives_written - pq->num_primitives_written[0]; 458 break; 459 case PIPE_QUERY_PRIMITIVES_GENERATED: 460 assert(llvmpipe->active_primgen_queries); 461 llvmpipe->active_primgen_queries--; 462 pq->num_primitives_generated[0] = 463 llvmpipe->so_stats[pq->index].primitives_storage_needed - pq->num_primitives_generated[0]; 464 break; 465 case PIPE_QUERY_SO_STATISTICS: 466 pq->num_primitives_written[0] = 467 llvmpipe->so_stats[pq->index].num_primitives_written - pq->num_primitives_written[0]; 468 pq->num_primitives_generated[0] = 469 llvmpipe->so_stats[pq->index].primitives_storage_needed - pq->num_primitives_generated[0]; 470 break; 471 case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE: 472 for (unsigned s = 0; s < PIPE_MAX_VERTEX_STREAMS; s++) { 473 pq->num_primitives_written[s] = 474 llvmpipe->so_stats[s].num_primitives_written - pq->num_primitives_written[s]; 475 pq->num_primitives_generated[s] = 476 llvmpipe->so_stats[s].primitives_storage_needed - pq->num_primitives_generated[s]; 477 } 478 break; 479 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: 480 pq->num_primitives_written[0] = 481 llvmpipe->so_stats[pq->index].num_primitives_written - pq->num_primitives_written[0]; 482 pq->num_primitives_generated[0] = 483 llvmpipe->so_stats[pq->index].primitives_storage_needed - pq->num_primitives_generated[0]; 484 break; 485 case PIPE_QUERY_PIPELINE_STATISTICS: 486 pq->stats.ia_vertices = 487 llvmpipe->pipeline_statistics.ia_vertices - pq->stats.ia_vertices; 488 pq->stats.ia_primitives = 489 llvmpipe->pipeline_statistics.ia_primitives - pq->stats.ia_primitives; 490 pq->stats.vs_invocations = 491 llvmpipe->pipeline_statistics.vs_invocations - pq->stats.vs_invocations; 492 pq->stats.gs_invocations = 493 llvmpipe->pipeline_statistics.gs_invocations - pq->stats.gs_invocations; 494 pq->stats.gs_primitives = 495 llvmpipe->pipeline_statistics.gs_primitives - pq->stats.gs_primitives; 496 pq->stats.c_invocations = 497 llvmpipe->pipeline_statistics.c_invocations - pq->stats.c_invocations; 498 pq->stats.c_primitives = 499 llvmpipe->pipeline_statistics.c_primitives - pq->stats.c_primitives; 500 pq->stats.ps_invocations = 501 llvmpipe->pipeline_statistics.ps_invocations - pq->stats.ps_invocations; 502 pq->stats.cs_invocations = 503 llvmpipe->pipeline_statistics.cs_invocations - pq->stats.cs_invocations; 504 pq->stats.hs_invocations = 505 llvmpipe->pipeline_statistics.hs_invocations - pq->stats.hs_invocations; 506 pq->stats.ds_invocations = 507 llvmpipe->pipeline_statistics.ds_invocations - pq->stats.ds_invocations; 508 llvmpipe->active_statistics_queries--; 509 break; 510 case PIPE_QUERY_OCCLUSION_COUNTER: 511 case PIPE_QUERY_OCCLUSION_PREDICATE: 512 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 513 assert(llvmpipe->active_occlusion_queries); 514 llvmpipe->active_occlusion_queries--; 515 llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY; 516 break; 517 default: 518 break; 519 } 520 521 return true; 522} 523 524boolean 525llvmpipe_check_render_cond(struct llvmpipe_context *lp) 526{ 527 struct pipe_context *pipe = &lp->pipe; 528 boolean b, wait; 529 uint64_t result; 530 531 if (lp->render_cond_buffer) { 532 uint32_t data = *(uint32_t *)((char *)lp->render_cond_buffer->data + lp->render_cond_offset); 533 return (!data) == lp->render_cond_cond; 534 } 535 if (!lp->render_cond_query) 536 return TRUE; /* no query predicate, draw normally */ 537 538 wait = (lp->render_cond_mode == PIPE_RENDER_COND_WAIT || 539 lp->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT); 540 541 b = pipe->get_query_result(pipe, lp->render_cond_query, wait, (void*)&result); 542 if (b) 543 return ((!result) == lp->render_cond_cond); 544 else 545 return TRUE; 546} 547 548static void 549llvmpipe_set_active_query_state(struct pipe_context *pipe, bool enable) 550{ 551 struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe); 552 553 llvmpipe->queries_disabled = !enable; 554 /* for OQs we need to regenerate the fragment shader */ 555 llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY; 556} 557 558void llvmpipe_init_query_funcs(struct llvmpipe_context *llvmpipe ) 559{ 560 llvmpipe->pipe.create_query = llvmpipe_create_query; 561 llvmpipe->pipe.destroy_query = llvmpipe_destroy_query; 562 llvmpipe->pipe.begin_query = llvmpipe_begin_query; 563 llvmpipe->pipe.end_query = llvmpipe_end_query; 564 llvmpipe->pipe.get_query_result = llvmpipe_get_query_result; 565 llvmpipe->pipe.get_query_result_resource = llvmpipe_get_query_result_resource; 566 llvmpipe->pipe.set_active_query_state = llvmpipe_set_active_query_state; 567} 568 569 570