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