queryobj.c revision 848b8605
1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 26#include "glheader.h" 27#include "context.h" 28#include "enums.h" 29#include "hash.h" 30#include "imports.h" 31#include "queryobj.h" 32#include "mtypes.h" 33#include "main/dispatch.h" 34 35 36/** 37 * Allocate a new query object. This is a fallback routine called via 38 * ctx->Driver.NewQueryObject(). 39 * \param ctx - rendering context 40 * \param id - the new object's ID 41 * \return pointer to new query_object object or NULL if out of memory. 42 */ 43static struct gl_query_object * 44_mesa_new_query_object(struct gl_context *ctx, GLuint id) 45{ 46 struct gl_query_object *q = CALLOC_STRUCT(gl_query_object); 47 (void) ctx; 48 if (q) { 49 q->Id = id; 50 q->Result = 0; 51 q->Active = GL_FALSE; 52 53 /* This is to satisfy the language of the specification: "In the initial 54 * state of a query object, the result is available" (OpenGL 3.1 § 55 * 2.13). 56 */ 57 q->Ready = GL_TRUE; 58 59 /* OpenGL 3.1 § 2.13 says about GenQueries, "These names are marked as 60 * used, but no object is associated with them until the first time they 61 * are used by BeginQuery." Since our implementation actually does 62 * allocate an object at this point, use a flag to indicate that this 63 * object has not yet been bound so should not be considered a query. 64 */ 65 q->EverBound = GL_FALSE; 66 } 67 return q; 68} 69 70 71/** 72 * Begin a query. Software driver fallback. 73 * Called via ctx->Driver.BeginQuery(). 74 */ 75static void 76_mesa_begin_query(struct gl_context *ctx, struct gl_query_object *q) 77{ 78 ctx->NewState |= _NEW_DEPTH; /* for swrast */ 79} 80 81 82/** 83 * End a query. Software driver fallback. 84 * Called via ctx->Driver.EndQuery(). 85 */ 86static void 87_mesa_end_query(struct gl_context *ctx, struct gl_query_object *q) 88{ 89 ctx->NewState |= _NEW_DEPTH; /* for swrast */ 90 q->Ready = GL_TRUE; 91} 92 93 94/** 95 * Wait for query to complete. Software driver fallback. 96 * Called via ctx->Driver.WaitQuery(). 97 */ 98static void 99_mesa_wait_query(struct gl_context *ctx, struct gl_query_object *q) 100{ 101 /* For software drivers, _mesa_end_query() should have completed the query. 102 * For real hardware, implement a proper WaitQuery() driver function, 103 * which may require issuing a flush. 104 */ 105 assert(q->Ready); 106} 107 108 109/** 110 * Check if a query results are ready. Software driver fallback. 111 * Called via ctx->Driver.CheckQuery(). 112 */ 113static void 114_mesa_check_query(struct gl_context *ctx, struct gl_query_object *q) 115{ 116 /* No-op for sw rendering. 117 * HW drivers may need to flush at this time. 118 */ 119} 120 121 122/** 123 * Delete a query object. Called via ctx->Driver.DeleteQuery(). 124 * Not removed from hash table here. 125 */ 126static void 127_mesa_delete_query(struct gl_context *ctx, struct gl_query_object *q) 128{ 129 free(q->Label); 130 free(q); 131} 132 133 134void 135_mesa_init_query_object_functions(struct dd_function_table *driver) 136{ 137 driver->NewQueryObject = _mesa_new_query_object; 138 driver->DeleteQuery = _mesa_delete_query; 139 driver->BeginQuery = _mesa_begin_query; 140 driver->EndQuery = _mesa_end_query; 141 driver->WaitQuery = _mesa_wait_query; 142 driver->CheckQuery = _mesa_check_query; 143} 144 145 146/** 147 * Return pointer to the query object binding point for the given target and 148 * index. 149 * \return NULL if invalid target, else the address of binding point 150 */ 151static struct gl_query_object ** 152get_query_binding_point(struct gl_context *ctx, GLenum target, GLuint index) 153{ 154 switch (target) { 155 case GL_SAMPLES_PASSED_ARB: 156 if (ctx->Extensions.ARB_occlusion_query) 157 return &ctx->Query.CurrentOcclusionObject; 158 else 159 return NULL; 160 case GL_ANY_SAMPLES_PASSED: 161 if (ctx->Extensions.ARB_occlusion_query2) 162 return &ctx->Query.CurrentOcclusionObject; 163 else 164 return NULL; 165 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: 166 if (ctx->Extensions.ARB_ES3_compatibility 167 || (ctx->API == API_OPENGLES2 && ctx->Version >= 30)) 168 return &ctx->Query.CurrentOcclusionObject; 169 else 170 return NULL; 171 case GL_TIME_ELAPSED_EXT: 172 if (ctx->Extensions.EXT_timer_query) 173 return &ctx->Query.CurrentTimerObject; 174 else 175 return NULL; 176 case GL_PRIMITIVES_GENERATED: 177 if (ctx->Extensions.EXT_transform_feedback) 178 return &ctx->Query.PrimitivesGenerated[index]; 179 else 180 return NULL; 181 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 182 if (ctx->Extensions.EXT_transform_feedback) 183 return &ctx->Query.PrimitivesWritten[index]; 184 else 185 return NULL; 186 default: 187 return NULL; 188 } 189} 190 191 192void GLAPIENTRY 193_mesa_GenQueries(GLsizei n, GLuint *ids) 194{ 195 GLuint first; 196 GET_CURRENT_CONTEXT(ctx); 197 198 if (MESA_VERBOSE & VERBOSE_API) 199 _mesa_debug(ctx, "glGenQueries(%d)\n", n); 200 201 if (n < 0) { 202 _mesa_error(ctx, GL_INVALID_VALUE, "glGenQueriesARB(n < 0)"); 203 return; 204 } 205 206 first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n); 207 if (first) { 208 GLsizei i; 209 for (i = 0; i < n; i++) { 210 struct gl_query_object *q 211 = ctx->Driver.NewQueryObject(ctx, first + i); 212 if (!q) { 213 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenQueriesARB"); 214 return; 215 } 216 ids[i] = first + i; 217 _mesa_HashInsert(ctx->Query.QueryObjects, first + i, q); 218 } 219 } 220} 221 222 223void GLAPIENTRY 224_mesa_DeleteQueries(GLsizei n, const GLuint *ids) 225{ 226 GLint i; 227 GET_CURRENT_CONTEXT(ctx); 228 FLUSH_VERTICES(ctx, 0); 229 230 if (MESA_VERBOSE & VERBOSE_API) 231 _mesa_debug(ctx, "glDeleteQueries(%d)\n", n); 232 233 if (n < 0) { 234 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)"); 235 return; 236 } 237 238 for (i = 0; i < n; i++) { 239 if (ids[i] > 0) { 240 struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]); 241 if (q) { 242 if (q->Active) { 243 struct gl_query_object **bindpt; 244 bindpt = get_query_binding_point(ctx, q->Target, q->Stream); 245 assert(bindpt); /* Should be non-null for active q. */ 246 if (bindpt) { 247 *bindpt = NULL; 248 } 249 q->Active = GL_FALSE; 250 ctx->Driver.EndQuery(ctx, q); 251 } 252 _mesa_HashRemove(ctx->Query.QueryObjects, ids[i]); 253 ctx->Driver.DeleteQuery(ctx, q); 254 } 255 } 256 } 257} 258 259 260GLboolean GLAPIENTRY 261_mesa_IsQuery(GLuint id) 262{ 263 struct gl_query_object *q; 264 265 GET_CURRENT_CONTEXT(ctx); 266 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 267 268 if (MESA_VERBOSE & VERBOSE_API) 269 _mesa_debug(ctx, "glIsQuery(%u)\n", id); 270 271 if (id == 0) 272 return GL_FALSE; 273 274 q = _mesa_lookup_query_object(ctx, id); 275 if (q == NULL) 276 return GL_FALSE; 277 278 return q->EverBound; 279} 280 281static GLboolean 282query_error_check_index(struct gl_context *ctx, GLenum target, GLuint index) 283{ 284 switch (target) { 285 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 286 case GL_PRIMITIVES_GENERATED: 287 if (index >= ctx->Const.MaxVertexStreams) { 288 _mesa_error(ctx, GL_INVALID_VALUE, 289 "glBeginQueryIndexed(index>=MaxVertexStreams)"); 290 return GL_FALSE; 291 } 292 break; 293 default: 294 if (index > 0) { 295 _mesa_error(ctx, GL_INVALID_VALUE, "glBeginQueryIndexed(index>0)"); 296 return GL_FALSE; 297 } 298 } 299 return GL_TRUE; 300} 301 302void GLAPIENTRY 303_mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id) 304{ 305 struct gl_query_object *q, **bindpt; 306 GET_CURRENT_CONTEXT(ctx); 307 308 if (MESA_VERBOSE & VERBOSE_API) 309 _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n", 310 _mesa_lookup_enum_by_nr(target), index, id); 311 312 if (!query_error_check_index(ctx, target, index)) 313 return; 314 315 FLUSH_VERTICES(ctx, 0); 316 317 bindpt = get_query_binding_point(ctx, target, index); 318 if (!bindpt) { 319 _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)"); 320 return; 321 } 322 323 /* From the GL_ARB_occlusion_query spec: 324 * 325 * "If BeginQueryARB is called while another query is already in 326 * progress with the same target, an INVALID_OPERATION error is 327 * generated." 328 */ 329 if (*bindpt) { 330 _mesa_error(ctx, GL_INVALID_OPERATION, 331 "glBeginQuery{Indexed}(target=%s is active)", 332 _mesa_lookup_enum_by_nr(target)); 333 return; 334 } 335 336 if (id == 0) { 337 _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)"); 338 return; 339 } 340 341 q = _mesa_lookup_query_object(ctx, id); 342 if (!q) { 343 if (ctx->API != API_OPENGL_COMPAT) { 344 _mesa_error(ctx, GL_INVALID_OPERATION, 345 "glBeginQuery{Indexed}(non-gen name)"); 346 return; 347 } else { 348 /* create new object */ 349 q = ctx->Driver.NewQueryObject(ctx, id); 350 if (!q) { 351 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}"); 352 return; 353 } 354 _mesa_HashInsert(ctx->Query.QueryObjects, id, q); 355 } 356 } 357 else { 358 /* pre-existing object */ 359 if (q->Active) { 360 _mesa_error(ctx, GL_INVALID_OPERATION, 361 "glBeginQuery{Indexed}(query already active)"); 362 return; 363 } 364 } 365 366 q->Target = target; 367 q->Active = GL_TRUE; 368 q->Result = 0; 369 q->Ready = GL_FALSE; 370 q->EverBound = GL_TRUE; 371 q->Stream = index; 372 373 /* XXX should probably refcount query objects */ 374 *bindpt = q; 375 376 ctx->Driver.BeginQuery(ctx, q); 377} 378 379 380void GLAPIENTRY 381_mesa_EndQueryIndexed(GLenum target, GLuint index) 382{ 383 struct gl_query_object *q, **bindpt; 384 GET_CURRENT_CONTEXT(ctx); 385 386 if (MESA_VERBOSE & VERBOSE_API) 387 _mesa_debug(ctx, "glEndQueryIndexed(%s, %u)\n", 388 _mesa_lookup_enum_by_nr(target), index); 389 390 if (!query_error_check_index(ctx, target, index)) 391 return; 392 393 FLUSH_VERTICES(ctx, 0); 394 395 bindpt = get_query_binding_point(ctx, target, index); 396 if (!bindpt) { 397 _mesa_error(ctx, GL_INVALID_ENUM, "glEndQuery{Indexed}(target)"); 398 return; 399 } 400 401 /* XXX should probably refcount query objects */ 402 q = *bindpt; 403 404 /* Check for GL_ANY_SAMPLES_PASSED vs GL_SAMPLES_PASSED. */ 405 if (q && q->Target != target) { 406 _mesa_error(ctx, GL_INVALID_OPERATION, 407 "glEndQuery(target=%s with active query of target %s)", 408 _mesa_lookup_enum_by_nr(target), 409 _mesa_lookup_enum_by_nr(q->Target)); 410 return; 411 } 412 413 *bindpt = NULL; 414 415 if (!q || !q->Active) { 416 _mesa_error(ctx, GL_INVALID_OPERATION, 417 "glEndQuery{Indexed}(no matching glBeginQuery{Indexed})"); 418 return; 419 } 420 421 q->Active = GL_FALSE; 422 ctx->Driver.EndQuery(ctx, q); 423} 424 425void GLAPIENTRY 426_mesa_BeginQuery(GLenum target, GLuint id) 427{ 428 _mesa_BeginQueryIndexed(target, 0, id); 429} 430 431void GLAPIENTRY 432_mesa_EndQuery(GLenum target) 433{ 434 _mesa_EndQueryIndexed(target, 0); 435} 436 437void GLAPIENTRY 438_mesa_QueryCounter(GLuint id, GLenum target) 439{ 440 struct gl_query_object *q; 441 GET_CURRENT_CONTEXT(ctx); 442 443 if (MESA_VERBOSE & VERBOSE_API) 444 _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id, 445 _mesa_lookup_enum_by_nr(target)); 446 447 /* error checking */ 448 if (target != GL_TIMESTAMP) { 449 _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)"); 450 return; 451 } 452 453 if (id == 0) { 454 _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)"); 455 return; 456 } 457 458 q = _mesa_lookup_query_object(ctx, id); 459 if (!q) { 460 /* XXX the Core profile should throw INVALID_OPERATION here */ 461 462 /* create new object */ 463 q = ctx->Driver.NewQueryObject(ctx, id); 464 if (!q) { 465 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter"); 466 return; 467 } 468 _mesa_HashInsert(ctx->Query.QueryObjects, id, q); 469 } 470 else { 471 if (q->Target && q->Target != GL_TIMESTAMP) { 472 _mesa_error(ctx, GL_INVALID_OPERATION, 473 "glQueryCounter(id has an invalid target)"); 474 return; 475 } 476 } 477 478 if (q->Active) { 479 _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)"); 480 return; 481 } 482 483 q->Target = target; 484 q->Result = 0; 485 q->Ready = GL_FALSE; 486 q->EverBound = GL_TRUE; 487 488 if (ctx->Driver.QueryCounter) { 489 ctx->Driver.QueryCounter(ctx, q); 490 } else { 491 /* QueryCounter is implemented using EndQuery without BeginQuery 492 * in drivers. This is actually Direct3D and Gallium convention. 493 */ 494 ctx->Driver.EndQuery(ctx, q); 495 } 496} 497 498 499void GLAPIENTRY 500_mesa_GetQueryIndexediv(GLenum target, GLuint index, GLenum pname, 501 GLint *params) 502{ 503 struct gl_query_object *q = NULL, **bindpt = NULL; 504 GET_CURRENT_CONTEXT(ctx); 505 506 if (MESA_VERBOSE & VERBOSE_API) 507 _mesa_debug(ctx, "glGetQueryIndexediv(%s, %u, %s)\n", 508 _mesa_lookup_enum_by_nr(target), 509 index, 510 _mesa_lookup_enum_by_nr(pname)); 511 512 if (!query_error_check_index(ctx, target, index)) 513 return; 514 515 if (target == GL_TIMESTAMP) { 516 if (!ctx->Extensions.ARB_timer_query) { 517 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)"); 518 return; 519 } 520 } 521 else { 522 bindpt = get_query_binding_point(ctx, target, index); 523 if (!bindpt) { 524 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(target)"); 525 return; 526 } 527 528 q = *bindpt; 529 } 530 531 switch (pname) { 532 case GL_QUERY_COUNTER_BITS_ARB: 533 switch (target) { 534 case GL_SAMPLES_PASSED: 535 *params = ctx->Const.QueryCounterBits.SamplesPassed; 536 break; 537 case GL_ANY_SAMPLES_PASSED: 538 /* The minimum value of this is 1 if it's nonzero, and the value 539 * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more 540 * bits. 541 */ 542 *params = 1; 543 break; 544 case GL_TIME_ELAPSED: 545 *params = ctx->Const.QueryCounterBits.TimeElapsed; 546 break; 547 case GL_TIMESTAMP: 548 *params = ctx->Const.QueryCounterBits.Timestamp; 549 break; 550 case GL_PRIMITIVES_GENERATED: 551 *params = ctx->Const.QueryCounterBits.PrimitivesGenerated; 552 break; 553 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 554 *params = ctx->Const.QueryCounterBits.PrimitivesWritten; 555 break; 556 default: 557 _mesa_problem(ctx, 558 "Unknown target in glGetQueryIndexediv(target = %s)", 559 _mesa_lookup_enum_by_nr(target)); 560 *params = 0; 561 break; 562 } 563 break; 564 case GL_CURRENT_QUERY_ARB: 565 *params = (q && q->Target == target) ? q->Id : 0; 566 break; 567 default: 568 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(pname)"); 569 return; 570 } 571} 572 573void GLAPIENTRY 574_mesa_GetQueryiv(GLenum target, GLenum pname, GLint *params) 575{ 576 _mesa_GetQueryIndexediv(target, 0, pname, params); 577} 578 579void GLAPIENTRY 580_mesa_GetQueryObjectiv(GLuint id, GLenum pname, GLint *params) 581{ 582 struct gl_query_object *q = NULL; 583 GET_CURRENT_CONTEXT(ctx); 584 585 if (MESA_VERBOSE & VERBOSE_API) 586 _mesa_debug(ctx, "glGetQueryObjectiv(%u, %s)\n", id, 587 _mesa_lookup_enum_by_nr(pname)); 588 589 if (id) 590 q = _mesa_lookup_query_object(ctx, id); 591 592 if (!q || q->Active) { 593 _mesa_error(ctx, GL_INVALID_OPERATION, 594 "glGetQueryObjectivARB(id=%d is invalid or active)", id); 595 return; 596 } 597 598 switch (pname) { 599 case GL_QUERY_RESULT_ARB: 600 if (!q->Ready) 601 ctx->Driver.WaitQuery(ctx, q); 602 /* if result is too large for returned type, clamp to max value */ 603 if (q->Target == GL_ANY_SAMPLES_PASSED 604 || q->Target == GL_ANY_SAMPLES_PASSED_CONSERVATIVE) { 605 if (q->Result) 606 *params = GL_TRUE; 607 else 608 *params = GL_FALSE; 609 } else { 610 if (q->Result > 0x7fffffff) { 611 *params = 0x7fffffff; 612 } 613 else { 614 *params = (GLint)q->Result; 615 } 616 } 617 break; 618 case GL_QUERY_RESULT_AVAILABLE_ARB: 619 if (!q->Ready) 620 ctx->Driver.CheckQuery( ctx, q ); 621 *params = q->Ready; 622 break; 623 default: 624 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)"); 625 return; 626 } 627} 628 629 630void GLAPIENTRY 631_mesa_GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params) 632{ 633 struct gl_query_object *q = NULL; 634 GET_CURRENT_CONTEXT(ctx); 635 636 if (MESA_VERBOSE & VERBOSE_API) 637 _mesa_debug(ctx, "glGetQueryObjectuiv(%u, %s)\n", id, 638 _mesa_lookup_enum_by_nr(pname)); 639 640 if (id) 641 q = _mesa_lookup_query_object(ctx, id); 642 643 if (!q || q->Active) { 644 _mesa_error(ctx, GL_INVALID_OPERATION, 645 "glGetQueryObjectuivARB(id=%d is invalid or active)", id); 646 return; 647 } 648 649 switch (pname) { 650 case GL_QUERY_RESULT_ARB: 651 if (!q->Ready) 652 ctx->Driver.WaitQuery(ctx, q); 653 /* if result is too large for returned type, clamp to max value */ 654 if (q->Target == GL_ANY_SAMPLES_PASSED 655 || q->Target == GL_ANY_SAMPLES_PASSED_CONSERVATIVE) { 656 if (q->Result) 657 *params = GL_TRUE; 658 else 659 *params = GL_FALSE; 660 } else { 661 if (q->Result > 0xffffffff) { 662 *params = 0xffffffff; 663 } 664 else { 665 *params = (GLuint)q->Result; 666 } 667 } 668 break; 669 case GL_QUERY_RESULT_AVAILABLE_ARB: 670 if (!q->Ready) 671 ctx->Driver.CheckQuery( ctx, q ); 672 *params = q->Ready; 673 break; 674 default: 675 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)"); 676 return; 677 } 678} 679 680 681/** 682 * New with GL_EXT_timer_query 683 */ 684void GLAPIENTRY 685_mesa_GetQueryObjecti64v(GLuint id, GLenum pname, GLint64EXT *params) 686{ 687 struct gl_query_object *q = NULL; 688 GET_CURRENT_CONTEXT(ctx); 689 690 if (MESA_VERBOSE & VERBOSE_API) 691 _mesa_debug(ctx, "glGetQueryObjecti64v(%u, %s)\n", id, 692 _mesa_lookup_enum_by_nr(pname)); 693 694 if (id) 695 q = _mesa_lookup_query_object(ctx, id); 696 697 if (!q || q->Active) { 698 _mesa_error(ctx, GL_INVALID_OPERATION, 699 "glGetQueryObjectui64vARB(id=%d is invalid or active)", id); 700 return; 701 } 702 703 switch (pname) { 704 case GL_QUERY_RESULT_ARB: 705 if (!q->Ready) 706 ctx->Driver.WaitQuery(ctx, q); 707 *params = q->Result; 708 break; 709 case GL_QUERY_RESULT_AVAILABLE_ARB: 710 if (!q->Ready) 711 ctx->Driver.CheckQuery( ctx, q ); 712 *params = q->Ready; 713 break; 714 default: 715 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjecti64vARB(pname)"); 716 return; 717 } 718} 719 720 721/** 722 * New with GL_EXT_timer_query 723 */ 724void GLAPIENTRY 725_mesa_GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64EXT *params) 726{ 727 struct gl_query_object *q = NULL; 728 GET_CURRENT_CONTEXT(ctx); 729 730 if (MESA_VERBOSE & VERBOSE_API) 731 _mesa_debug(ctx, "glGetQueryObjectui64v(%u, %s)\n", id, 732 _mesa_lookup_enum_by_nr(pname)); 733 734 if (id) 735 q = _mesa_lookup_query_object(ctx, id); 736 737 if (!q || q->Active) { 738 _mesa_error(ctx, GL_INVALID_OPERATION, 739 "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id); 740 return; 741 } 742 743 switch (pname) { 744 case GL_QUERY_RESULT_ARB: 745 if (!q->Ready) 746 ctx->Driver.WaitQuery(ctx, q); 747 *params = q->Result; 748 break; 749 case GL_QUERY_RESULT_AVAILABLE_ARB: 750 if (!q->Ready) 751 ctx->Driver.CheckQuery( ctx, q ); 752 *params = q->Ready; 753 break; 754 default: 755 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectui64vARB(pname)"); 756 return; 757 } 758} 759 760/** 761 * Allocate/init the context state related to query objects. 762 */ 763void 764_mesa_init_queryobj(struct gl_context *ctx) 765{ 766 ctx->Query.QueryObjects = _mesa_NewHashTable(); 767 ctx->Query.CurrentOcclusionObject = NULL; 768 769 ctx->Const.QueryCounterBits.SamplesPassed = 64; 770 ctx->Const.QueryCounterBits.TimeElapsed = 64; 771 ctx->Const.QueryCounterBits.Timestamp = 64; 772 ctx->Const.QueryCounterBits.PrimitivesGenerated = 64; 773 ctx->Const.QueryCounterBits.PrimitivesWritten = 64; 774} 775 776 777/** 778 * Callback for deleting a query object. Called by _mesa_HashDeleteAll(). 779 */ 780static void 781delete_queryobj_cb(GLuint id, void *data, void *userData) 782{ 783 struct gl_query_object *q= (struct gl_query_object *) data; 784 struct gl_context *ctx = (struct gl_context *)userData; 785 ctx->Driver.DeleteQuery(ctx, q); 786} 787 788 789/** 790 * Free the context state related to query objects. 791 */ 792void 793_mesa_free_queryobj_data(struct gl_context *ctx) 794{ 795 _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx); 796 _mesa_DeleteHashTable(ctx->Query.QueryObjects); 797} 798