queryobj.c revision 848b8605
1848b8605Smrg/* 2848b8605Smrg * Mesa 3-D graphics library 3848b8605Smrg * 4848b8605Smrg * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 5848b8605Smrg * 6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7848b8605Smrg * copy of this software and associated documentation files (the "Software"), 8848b8605Smrg * to deal in the Software without restriction, including without limitation 9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 11848b8605Smrg * Software is furnished to do so, subject to the following conditions: 12848b8605Smrg * 13848b8605Smrg * The above copyright notice and this permission notice shall be included 14848b8605Smrg * in all copies or substantial portions of the Software. 15848b8605Smrg * 16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 23848b8605Smrg */ 24848b8605Smrg 25848b8605Smrg 26848b8605Smrg#include "glheader.h" 27848b8605Smrg#include "context.h" 28848b8605Smrg#include "enums.h" 29848b8605Smrg#include "hash.h" 30848b8605Smrg#include "imports.h" 31848b8605Smrg#include "queryobj.h" 32848b8605Smrg#include "mtypes.h" 33848b8605Smrg#include "main/dispatch.h" 34848b8605Smrg 35848b8605Smrg 36848b8605Smrg/** 37848b8605Smrg * Allocate a new query object. This is a fallback routine called via 38848b8605Smrg * ctx->Driver.NewQueryObject(). 39848b8605Smrg * \param ctx - rendering context 40848b8605Smrg * \param id - the new object's ID 41848b8605Smrg * \return pointer to new query_object object or NULL if out of memory. 42848b8605Smrg */ 43848b8605Smrgstatic struct gl_query_object * 44848b8605Smrg_mesa_new_query_object(struct gl_context *ctx, GLuint id) 45848b8605Smrg{ 46848b8605Smrg struct gl_query_object *q = CALLOC_STRUCT(gl_query_object); 47848b8605Smrg (void) ctx; 48848b8605Smrg if (q) { 49848b8605Smrg q->Id = id; 50848b8605Smrg q->Result = 0; 51848b8605Smrg q->Active = GL_FALSE; 52848b8605Smrg 53848b8605Smrg /* This is to satisfy the language of the specification: "In the initial 54848b8605Smrg * state of a query object, the result is available" (OpenGL 3.1 § 55848b8605Smrg * 2.13). 56848b8605Smrg */ 57848b8605Smrg q->Ready = GL_TRUE; 58848b8605Smrg 59848b8605Smrg /* OpenGL 3.1 § 2.13 says about GenQueries, "These names are marked as 60848b8605Smrg * used, but no object is associated with them until the first time they 61848b8605Smrg * are used by BeginQuery." Since our implementation actually does 62848b8605Smrg * allocate an object at this point, use a flag to indicate that this 63848b8605Smrg * object has not yet been bound so should not be considered a query. 64848b8605Smrg */ 65848b8605Smrg q->EverBound = GL_FALSE; 66848b8605Smrg } 67848b8605Smrg return q; 68848b8605Smrg} 69848b8605Smrg 70848b8605Smrg 71848b8605Smrg/** 72848b8605Smrg * Begin a query. Software driver fallback. 73848b8605Smrg * Called via ctx->Driver.BeginQuery(). 74848b8605Smrg */ 75848b8605Smrgstatic void 76848b8605Smrg_mesa_begin_query(struct gl_context *ctx, struct gl_query_object *q) 77848b8605Smrg{ 78848b8605Smrg ctx->NewState |= _NEW_DEPTH; /* for swrast */ 79848b8605Smrg} 80848b8605Smrg 81848b8605Smrg 82848b8605Smrg/** 83848b8605Smrg * End a query. Software driver fallback. 84848b8605Smrg * Called via ctx->Driver.EndQuery(). 85848b8605Smrg */ 86848b8605Smrgstatic void 87848b8605Smrg_mesa_end_query(struct gl_context *ctx, struct gl_query_object *q) 88848b8605Smrg{ 89848b8605Smrg ctx->NewState |= _NEW_DEPTH; /* for swrast */ 90848b8605Smrg q->Ready = GL_TRUE; 91848b8605Smrg} 92848b8605Smrg 93848b8605Smrg 94848b8605Smrg/** 95848b8605Smrg * Wait for query to complete. Software driver fallback. 96848b8605Smrg * Called via ctx->Driver.WaitQuery(). 97848b8605Smrg */ 98848b8605Smrgstatic void 99848b8605Smrg_mesa_wait_query(struct gl_context *ctx, struct gl_query_object *q) 100848b8605Smrg{ 101848b8605Smrg /* For software drivers, _mesa_end_query() should have completed the query. 102848b8605Smrg * For real hardware, implement a proper WaitQuery() driver function, 103848b8605Smrg * which may require issuing a flush. 104848b8605Smrg */ 105848b8605Smrg assert(q->Ready); 106848b8605Smrg} 107848b8605Smrg 108848b8605Smrg 109848b8605Smrg/** 110848b8605Smrg * Check if a query results are ready. Software driver fallback. 111848b8605Smrg * Called via ctx->Driver.CheckQuery(). 112848b8605Smrg */ 113848b8605Smrgstatic void 114848b8605Smrg_mesa_check_query(struct gl_context *ctx, struct gl_query_object *q) 115848b8605Smrg{ 116848b8605Smrg /* No-op for sw rendering. 117848b8605Smrg * HW drivers may need to flush at this time. 118848b8605Smrg */ 119848b8605Smrg} 120848b8605Smrg 121848b8605Smrg 122848b8605Smrg/** 123848b8605Smrg * Delete a query object. Called via ctx->Driver.DeleteQuery(). 124848b8605Smrg * Not removed from hash table here. 125848b8605Smrg */ 126848b8605Smrgstatic void 127848b8605Smrg_mesa_delete_query(struct gl_context *ctx, struct gl_query_object *q) 128848b8605Smrg{ 129848b8605Smrg free(q->Label); 130848b8605Smrg free(q); 131848b8605Smrg} 132848b8605Smrg 133848b8605Smrg 134848b8605Smrgvoid 135848b8605Smrg_mesa_init_query_object_functions(struct dd_function_table *driver) 136848b8605Smrg{ 137848b8605Smrg driver->NewQueryObject = _mesa_new_query_object; 138848b8605Smrg driver->DeleteQuery = _mesa_delete_query; 139848b8605Smrg driver->BeginQuery = _mesa_begin_query; 140848b8605Smrg driver->EndQuery = _mesa_end_query; 141848b8605Smrg driver->WaitQuery = _mesa_wait_query; 142848b8605Smrg driver->CheckQuery = _mesa_check_query; 143848b8605Smrg} 144848b8605Smrg 145848b8605Smrg 146848b8605Smrg/** 147848b8605Smrg * Return pointer to the query object binding point for the given target and 148848b8605Smrg * index. 149848b8605Smrg * \return NULL if invalid target, else the address of binding point 150848b8605Smrg */ 151848b8605Smrgstatic struct gl_query_object ** 152848b8605Smrgget_query_binding_point(struct gl_context *ctx, GLenum target, GLuint index) 153848b8605Smrg{ 154848b8605Smrg switch (target) { 155848b8605Smrg case GL_SAMPLES_PASSED_ARB: 156848b8605Smrg if (ctx->Extensions.ARB_occlusion_query) 157848b8605Smrg return &ctx->Query.CurrentOcclusionObject; 158848b8605Smrg else 159848b8605Smrg return NULL; 160848b8605Smrg case GL_ANY_SAMPLES_PASSED: 161848b8605Smrg if (ctx->Extensions.ARB_occlusion_query2) 162848b8605Smrg return &ctx->Query.CurrentOcclusionObject; 163848b8605Smrg else 164848b8605Smrg return NULL; 165848b8605Smrg case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: 166848b8605Smrg if (ctx->Extensions.ARB_ES3_compatibility 167848b8605Smrg || (ctx->API == API_OPENGLES2 && ctx->Version >= 30)) 168848b8605Smrg return &ctx->Query.CurrentOcclusionObject; 169848b8605Smrg else 170848b8605Smrg return NULL; 171848b8605Smrg case GL_TIME_ELAPSED_EXT: 172848b8605Smrg if (ctx->Extensions.EXT_timer_query) 173848b8605Smrg return &ctx->Query.CurrentTimerObject; 174848b8605Smrg else 175848b8605Smrg return NULL; 176848b8605Smrg case GL_PRIMITIVES_GENERATED: 177848b8605Smrg if (ctx->Extensions.EXT_transform_feedback) 178848b8605Smrg return &ctx->Query.PrimitivesGenerated[index]; 179848b8605Smrg else 180848b8605Smrg return NULL; 181848b8605Smrg case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 182848b8605Smrg if (ctx->Extensions.EXT_transform_feedback) 183848b8605Smrg return &ctx->Query.PrimitivesWritten[index]; 184848b8605Smrg else 185848b8605Smrg return NULL; 186848b8605Smrg default: 187848b8605Smrg return NULL; 188848b8605Smrg } 189848b8605Smrg} 190848b8605Smrg 191848b8605Smrg 192848b8605Smrgvoid GLAPIENTRY 193848b8605Smrg_mesa_GenQueries(GLsizei n, GLuint *ids) 194848b8605Smrg{ 195848b8605Smrg GLuint first; 196848b8605Smrg GET_CURRENT_CONTEXT(ctx); 197848b8605Smrg 198848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 199848b8605Smrg _mesa_debug(ctx, "glGenQueries(%d)\n", n); 200848b8605Smrg 201848b8605Smrg if (n < 0) { 202848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glGenQueriesARB(n < 0)"); 203848b8605Smrg return; 204848b8605Smrg } 205848b8605Smrg 206848b8605Smrg first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n); 207848b8605Smrg if (first) { 208848b8605Smrg GLsizei i; 209848b8605Smrg for (i = 0; i < n; i++) { 210848b8605Smrg struct gl_query_object *q 211848b8605Smrg = ctx->Driver.NewQueryObject(ctx, first + i); 212848b8605Smrg if (!q) { 213848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenQueriesARB"); 214848b8605Smrg return; 215848b8605Smrg } 216848b8605Smrg ids[i] = first + i; 217848b8605Smrg _mesa_HashInsert(ctx->Query.QueryObjects, first + i, q); 218848b8605Smrg } 219848b8605Smrg } 220848b8605Smrg} 221848b8605Smrg 222848b8605Smrg 223848b8605Smrgvoid GLAPIENTRY 224848b8605Smrg_mesa_DeleteQueries(GLsizei n, const GLuint *ids) 225848b8605Smrg{ 226848b8605Smrg GLint i; 227848b8605Smrg GET_CURRENT_CONTEXT(ctx); 228848b8605Smrg FLUSH_VERTICES(ctx, 0); 229848b8605Smrg 230848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 231848b8605Smrg _mesa_debug(ctx, "glDeleteQueries(%d)\n", n); 232848b8605Smrg 233848b8605Smrg if (n < 0) { 234848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)"); 235848b8605Smrg return; 236848b8605Smrg } 237848b8605Smrg 238848b8605Smrg for (i = 0; i < n; i++) { 239848b8605Smrg if (ids[i] > 0) { 240848b8605Smrg struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]); 241848b8605Smrg if (q) { 242848b8605Smrg if (q->Active) { 243848b8605Smrg struct gl_query_object **bindpt; 244848b8605Smrg bindpt = get_query_binding_point(ctx, q->Target, q->Stream); 245848b8605Smrg assert(bindpt); /* Should be non-null for active q. */ 246848b8605Smrg if (bindpt) { 247848b8605Smrg *bindpt = NULL; 248848b8605Smrg } 249848b8605Smrg q->Active = GL_FALSE; 250848b8605Smrg ctx->Driver.EndQuery(ctx, q); 251848b8605Smrg } 252848b8605Smrg _mesa_HashRemove(ctx->Query.QueryObjects, ids[i]); 253848b8605Smrg ctx->Driver.DeleteQuery(ctx, q); 254848b8605Smrg } 255848b8605Smrg } 256848b8605Smrg } 257848b8605Smrg} 258848b8605Smrg 259848b8605Smrg 260848b8605SmrgGLboolean GLAPIENTRY 261848b8605Smrg_mesa_IsQuery(GLuint id) 262848b8605Smrg{ 263848b8605Smrg struct gl_query_object *q; 264848b8605Smrg 265848b8605Smrg GET_CURRENT_CONTEXT(ctx); 266848b8605Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 267848b8605Smrg 268848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 269848b8605Smrg _mesa_debug(ctx, "glIsQuery(%u)\n", id); 270848b8605Smrg 271848b8605Smrg if (id == 0) 272848b8605Smrg return GL_FALSE; 273848b8605Smrg 274848b8605Smrg q = _mesa_lookup_query_object(ctx, id); 275848b8605Smrg if (q == NULL) 276848b8605Smrg return GL_FALSE; 277848b8605Smrg 278848b8605Smrg return q->EverBound; 279848b8605Smrg} 280848b8605Smrg 281848b8605Smrgstatic GLboolean 282848b8605Smrgquery_error_check_index(struct gl_context *ctx, GLenum target, GLuint index) 283848b8605Smrg{ 284848b8605Smrg switch (target) { 285848b8605Smrg case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 286848b8605Smrg case GL_PRIMITIVES_GENERATED: 287848b8605Smrg if (index >= ctx->Const.MaxVertexStreams) { 288848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 289848b8605Smrg "glBeginQueryIndexed(index>=MaxVertexStreams)"); 290848b8605Smrg return GL_FALSE; 291848b8605Smrg } 292848b8605Smrg break; 293848b8605Smrg default: 294848b8605Smrg if (index > 0) { 295848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glBeginQueryIndexed(index>0)"); 296848b8605Smrg return GL_FALSE; 297848b8605Smrg } 298848b8605Smrg } 299848b8605Smrg return GL_TRUE; 300848b8605Smrg} 301848b8605Smrg 302848b8605Smrgvoid GLAPIENTRY 303848b8605Smrg_mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id) 304848b8605Smrg{ 305848b8605Smrg struct gl_query_object *q, **bindpt; 306848b8605Smrg GET_CURRENT_CONTEXT(ctx); 307848b8605Smrg 308848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 309848b8605Smrg _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n", 310848b8605Smrg _mesa_lookup_enum_by_nr(target), index, id); 311848b8605Smrg 312848b8605Smrg if (!query_error_check_index(ctx, target, index)) 313848b8605Smrg return; 314848b8605Smrg 315848b8605Smrg FLUSH_VERTICES(ctx, 0); 316848b8605Smrg 317848b8605Smrg bindpt = get_query_binding_point(ctx, target, index); 318848b8605Smrg if (!bindpt) { 319848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)"); 320848b8605Smrg return; 321848b8605Smrg } 322848b8605Smrg 323848b8605Smrg /* From the GL_ARB_occlusion_query spec: 324848b8605Smrg * 325848b8605Smrg * "If BeginQueryARB is called while another query is already in 326848b8605Smrg * progress with the same target, an INVALID_OPERATION error is 327848b8605Smrg * generated." 328848b8605Smrg */ 329848b8605Smrg if (*bindpt) { 330848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 331848b8605Smrg "glBeginQuery{Indexed}(target=%s is active)", 332848b8605Smrg _mesa_lookup_enum_by_nr(target)); 333848b8605Smrg return; 334848b8605Smrg } 335848b8605Smrg 336848b8605Smrg if (id == 0) { 337848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)"); 338848b8605Smrg return; 339848b8605Smrg } 340848b8605Smrg 341848b8605Smrg q = _mesa_lookup_query_object(ctx, id); 342848b8605Smrg if (!q) { 343848b8605Smrg if (ctx->API != API_OPENGL_COMPAT) { 344848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 345848b8605Smrg "glBeginQuery{Indexed}(non-gen name)"); 346848b8605Smrg return; 347848b8605Smrg } else { 348848b8605Smrg /* create new object */ 349848b8605Smrg q = ctx->Driver.NewQueryObject(ctx, id); 350848b8605Smrg if (!q) { 351848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}"); 352848b8605Smrg return; 353848b8605Smrg } 354848b8605Smrg _mesa_HashInsert(ctx->Query.QueryObjects, id, q); 355848b8605Smrg } 356848b8605Smrg } 357848b8605Smrg else { 358848b8605Smrg /* pre-existing object */ 359848b8605Smrg if (q->Active) { 360848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 361848b8605Smrg "glBeginQuery{Indexed}(query already active)"); 362848b8605Smrg return; 363848b8605Smrg } 364848b8605Smrg } 365848b8605Smrg 366848b8605Smrg q->Target = target; 367848b8605Smrg q->Active = GL_TRUE; 368848b8605Smrg q->Result = 0; 369848b8605Smrg q->Ready = GL_FALSE; 370848b8605Smrg q->EverBound = GL_TRUE; 371848b8605Smrg q->Stream = index; 372848b8605Smrg 373848b8605Smrg /* XXX should probably refcount query objects */ 374848b8605Smrg *bindpt = q; 375848b8605Smrg 376848b8605Smrg ctx->Driver.BeginQuery(ctx, q); 377848b8605Smrg} 378848b8605Smrg 379848b8605Smrg 380848b8605Smrgvoid GLAPIENTRY 381848b8605Smrg_mesa_EndQueryIndexed(GLenum target, GLuint index) 382848b8605Smrg{ 383848b8605Smrg struct gl_query_object *q, **bindpt; 384848b8605Smrg GET_CURRENT_CONTEXT(ctx); 385848b8605Smrg 386848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 387848b8605Smrg _mesa_debug(ctx, "glEndQueryIndexed(%s, %u)\n", 388848b8605Smrg _mesa_lookup_enum_by_nr(target), index); 389848b8605Smrg 390848b8605Smrg if (!query_error_check_index(ctx, target, index)) 391848b8605Smrg return; 392848b8605Smrg 393848b8605Smrg FLUSH_VERTICES(ctx, 0); 394848b8605Smrg 395848b8605Smrg bindpt = get_query_binding_point(ctx, target, index); 396848b8605Smrg if (!bindpt) { 397848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glEndQuery{Indexed}(target)"); 398848b8605Smrg return; 399848b8605Smrg } 400848b8605Smrg 401848b8605Smrg /* XXX should probably refcount query objects */ 402848b8605Smrg q = *bindpt; 403848b8605Smrg 404848b8605Smrg /* Check for GL_ANY_SAMPLES_PASSED vs GL_SAMPLES_PASSED. */ 405848b8605Smrg if (q && q->Target != target) { 406848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 407848b8605Smrg "glEndQuery(target=%s with active query of target %s)", 408848b8605Smrg _mesa_lookup_enum_by_nr(target), 409848b8605Smrg _mesa_lookup_enum_by_nr(q->Target)); 410848b8605Smrg return; 411848b8605Smrg } 412848b8605Smrg 413848b8605Smrg *bindpt = NULL; 414848b8605Smrg 415848b8605Smrg if (!q || !q->Active) { 416848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 417848b8605Smrg "glEndQuery{Indexed}(no matching glBeginQuery{Indexed})"); 418848b8605Smrg return; 419848b8605Smrg } 420848b8605Smrg 421848b8605Smrg q->Active = GL_FALSE; 422848b8605Smrg ctx->Driver.EndQuery(ctx, q); 423848b8605Smrg} 424848b8605Smrg 425848b8605Smrgvoid GLAPIENTRY 426848b8605Smrg_mesa_BeginQuery(GLenum target, GLuint id) 427848b8605Smrg{ 428848b8605Smrg _mesa_BeginQueryIndexed(target, 0, id); 429848b8605Smrg} 430848b8605Smrg 431848b8605Smrgvoid GLAPIENTRY 432848b8605Smrg_mesa_EndQuery(GLenum target) 433848b8605Smrg{ 434848b8605Smrg _mesa_EndQueryIndexed(target, 0); 435848b8605Smrg} 436848b8605Smrg 437848b8605Smrgvoid GLAPIENTRY 438848b8605Smrg_mesa_QueryCounter(GLuint id, GLenum target) 439848b8605Smrg{ 440848b8605Smrg struct gl_query_object *q; 441848b8605Smrg GET_CURRENT_CONTEXT(ctx); 442848b8605Smrg 443848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 444848b8605Smrg _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id, 445848b8605Smrg _mesa_lookup_enum_by_nr(target)); 446848b8605Smrg 447848b8605Smrg /* error checking */ 448848b8605Smrg if (target != GL_TIMESTAMP) { 449848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)"); 450848b8605Smrg return; 451848b8605Smrg } 452848b8605Smrg 453848b8605Smrg if (id == 0) { 454848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)"); 455848b8605Smrg return; 456848b8605Smrg } 457848b8605Smrg 458848b8605Smrg q = _mesa_lookup_query_object(ctx, id); 459848b8605Smrg if (!q) { 460848b8605Smrg /* XXX the Core profile should throw INVALID_OPERATION here */ 461848b8605Smrg 462848b8605Smrg /* create new object */ 463848b8605Smrg q = ctx->Driver.NewQueryObject(ctx, id); 464848b8605Smrg if (!q) { 465848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter"); 466848b8605Smrg return; 467848b8605Smrg } 468848b8605Smrg _mesa_HashInsert(ctx->Query.QueryObjects, id, q); 469848b8605Smrg } 470848b8605Smrg else { 471848b8605Smrg if (q->Target && q->Target != GL_TIMESTAMP) { 472848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 473848b8605Smrg "glQueryCounter(id has an invalid target)"); 474848b8605Smrg return; 475848b8605Smrg } 476848b8605Smrg } 477848b8605Smrg 478848b8605Smrg if (q->Active) { 479848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)"); 480848b8605Smrg return; 481848b8605Smrg } 482848b8605Smrg 483848b8605Smrg q->Target = target; 484848b8605Smrg q->Result = 0; 485848b8605Smrg q->Ready = GL_FALSE; 486848b8605Smrg q->EverBound = GL_TRUE; 487848b8605Smrg 488848b8605Smrg if (ctx->Driver.QueryCounter) { 489848b8605Smrg ctx->Driver.QueryCounter(ctx, q); 490848b8605Smrg } else { 491848b8605Smrg /* QueryCounter is implemented using EndQuery without BeginQuery 492848b8605Smrg * in drivers. This is actually Direct3D and Gallium convention. 493848b8605Smrg */ 494848b8605Smrg ctx->Driver.EndQuery(ctx, q); 495848b8605Smrg } 496848b8605Smrg} 497848b8605Smrg 498848b8605Smrg 499848b8605Smrgvoid GLAPIENTRY 500848b8605Smrg_mesa_GetQueryIndexediv(GLenum target, GLuint index, GLenum pname, 501848b8605Smrg GLint *params) 502848b8605Smrg{ 503848b8605Smrg struct gl_query_object *q = NULL, **bindpt = NULL; 504848b8605Smrg GET_CURRENT_CONTEXT(ctx); 505848b8605Smrg 506848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 507848b8605Smrg _mesa_debug(ctx, "glGetQueryIndexediv(%s, %u, %s)\n", 508848b8605Smrg _mesa_lookup_enum_by_nr(target), 509848b8605Smrg index, 510848b8605Smrg _mesa_lookup_enum_by_nr(pname)); 511848b8605Smrg 512848b8605Smrg if (!query_error_check_index(ctx, target, index)) 513848b8605Smrg return; 514848b8605Smrg 515848b8605Smrg if (target == GL_TIMESTAMP) { 516848b8605Smrg if (!ctx->Extensions.ARB_timer_query) { 517848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)"); 518848b8605Smrg return; 519848b8605Smrg } 520848b8605Smrg } 521848b8605Smrg else { 522848b8605Smrg bindpt = get_query_binding_point(ctx, target, index); 523848b8605Smrg if (!bindpt) { 524848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(target)"); 525848b8605Smrg return; 526848b8605Smrg } 527848b8605Smrg 528848b8605Smrg q = *bindpt; 529848b8605Smrg } 530848b8605Smrg 531848b8605Smrg switch (pname) { 532848b8605Smrg case GL_QUERY_COUNTER_BITS_ARB: 533848b8605Smrg switch (target) { 534848b8605Smrg case GL_SAMPLES_PASSED: 535848b8605Smrg *params = ctx->Const.QueryCounterBits.SamplesPassed; 536848b8605Smrg break; 537848b8605Smrg case GL_ANY_SAMPLES_PASSED: 538848b8605Smrg /* The minimum value of this is 1 if it's nonzero, and the value 539848b8605Smrg * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more 540848b8605Smrg * bits. 541848b8605Smrg */ 542848b8605Smrg *params = 1; 543848b8605Smrg break; 544848b8605Smrg case GL_TIME_ELAPSED: 545848b8605Smrg *params = ctx->Const.QueryCounterBits.TimeElapsed; 546848b8605Smrg break; 547848b8605Smrg case GL_TIMESTAMP: 548848b8605Smrg *params = ctx->Const.QueryCounterBits.Timestamp; 549848b8605Smrg break; 550848b8605Smrg case GL_PRIMITIVES_GENERATED: 551848b8605Smrg *params = ctx->Const.QueryCounterBits.PrimitivesGenerated; 552848b8605Smrg break; 553848b8605Smrg case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 554848b8605Smrg *params = ctx->Const.QueryCounterBits.PrimitivesWritten; 555848b8605Smrg break; 556848b8605Smrg default: 557848b8605Smrg _mesa_problem(ctx, 558848b8605Smrg "Unknown target in glGetQueryIndexediv(target = %s)", 559848b8605Smrg _mesa_lookup_enum_by_nr(target)); 560848b8605Smrg *params = 0; 561848b8605Smrg break; 562848b8605Smrg } 563848b8605Smrg break; 564848b8605Smrg case GL_CURRENT_QUERY_ARB: 565848b8605Smrg *params = (q && q->Target == target) ? q->Id : 0; 566848b8605Smrg break; 567848b8605Smrg default: 568848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(pname)"); 569848b8605Smrg return; 570848b8605Smrg } 571848b8605Smrg} 572848b8605Smrg 573848b8605Smrgvoid GLAPIENTRY 574848b8605Smrg_mesa_GetQueryiv(GLenum target, GLenum pname, GLint *params) 575848b8605Smrg{ 576848b8605Smrg _mesa_GetQueryIndexediv(target, 0, pname, params); 577848b8605Smrg} 578848b8605Smrg 579848b8605Smrgvoid GLAPIENTRY 580848b8605Smrg_mesa_GetQueryObjectiv(GLuint id, GLenum pname, GLint *params) 581848b8605Smrg{ 582848b8605Smrg struct gl_query_object *q = NULL; 583848b8605Smrg GET_CURRENT_CONTEXT(ctx); 584848b8605Smrg 585848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 586848b8605Smrg _mesa_debug(ctx, "glGetQueryObjectiv(%u, %s)\n", id, 587848b8605Smrg _mesa_lookup_enum_by_nr(pname)); 588848b8605Smrg 589848b8605Smrg if (id) 590848b8605Smrg q = _mesa_lookup_query_object(ctx, id); 591848b8605Smrg 592848b8605Smrg if (!q || q->Active) { 593848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 594848b8605Smrg "glGetQueryObjectivARB(id=%d is invalid or active)", id); 595848b8605Smrg return; 596848b8605Smrg } 597848b8605Smrg 598848b8605Smrg switch (pname) { 599848b8605Smrg case GL_QUERY_RESULT_ARB: 600848b8605Smrg if (!q->Ready) 601848b8605Smrg ctx->Driver.WaitQuery(ctx, q); 602848b8605Smrg /* if result is too large for returned type, clamp to max value */ 603848b8605Smrg if (q->Target == GL_ANY_SAMPLES_PASSED 604848b8605Smrg || q->Target == GL_ANY_SAMPLES_PASSED_CONSERVATIVE) { 605848b8605Smrg if (q->Result) 606848b8605Smrg *params = GL_TRUE; 607848b8605Smrg else 608848b8605Smrg *params = GL_FALSE; 609848b8605Smrg } else { 610848b8605Smrg if (q->Result > 0x7fffffff) { 611848b8605Smrg *params = 0x7fffffff; 612848b8605Smrg } 613848b8605Smrg else { 614848b8605Smrg *params = (GLint)q->Result; 615848b8605Smrg } 616848b8605Smrg } 617848b8605Smrg break; 618848b8605Smrg case GL_QUERY_RESULT_AVAILABLE_ARB: 619848b8605Smrg if (!q->Ready) 620848b8605Smrg ctx->Driver.CheckQuery( ctx, q ); 621848b8605Smrg *params = q->Ready; 622848b8605Smrg break; 623848b8605Smrg default: 624848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)"); 625848b8605Smrg return; 626848b8605Smrg } 627848b8605Smrg} 628848b8605Smrg 629848b8605Smrg 630848b8605Smrgvoid GLAPIENTRY 631848b8605Smrg_mesa_GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params) 632848b8605Smrg{ 633848b8605Smrg struct gl_query_object *q = NULL; 634848b8605Smrg GET_CURRENT_CONTEXT(ctx); 635848b8605Smrg 636848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 637848b8605Smrg _mesa_debug(ctx, "glGetQueryObjectuiv(%u, %s)\n", id, 638848b8605Smrg _mesa_lookup_enum_by_nr(pname)); 639848b8605Smrg 640848b8605Smrg if (id) 641848b8605Smrg q = _mesa_lookup_query_object(ctx, id); 642848b8605Smrg 643848b8605Smrg if (!q || q->Active) { 644848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 645848b8605Smrg "glGetQueryObjectuivARB(id=%d is invalid or active)", id); 646848b8605Smrg return; 647848b8605Smrg } 648848b8605Smrg 649848b8605Smrg switch (pname) { 650848b8605Smrg case GL_QUERY_RESULT_ARB: 651848b8605Smrg if (!q->Ready) 652848b8605Smrg ctx->Driver.WaitQuery(ctx, q); 653848b8605Smrg /* if result is too large for returned type, clamp to max value */ 654848b8605Smrg if (q->Target == GL_ANY_SAMPLES_PASSED 655848b8605Smrg || q->Target == GL_ANY_SAMPLES_PASSED_CONSERVATIVE) { 656848b8605Smrg if (q->Result) 657848b8605Smrg *params = GL_TRUE; 658848b8605Smrg else 659848b8605Smrg *params = GL_FALSE; 660848b8605Smrg } else { 661848b8605Smrg if (q->Result > 0xffffffff) { 662848b8605Smrg *params = 0xffffffff; 663848b8605Smrg } 664848b8605Smrg else { 665848b8605Smrg *params = (GLuint)q->Result; 666848b8605Smrg } 667848b8605Smrg } 668848b8605Smrg break; 669848b8605Smrg case GL_QUERY_RESULT_AVAILABLE_ARB: 670848b8605Smrg if (!q->Ready) 671848b8605Smrg ctx->Driver.CheckQuery( ctx, q ); 672848b8605Smrg *params = q->Ready; 673848b8605Smrg break; 674848b8605Smrg default: 675848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)"); 676848b8605Smrg return; 677848b8605Smrg } 678848b8605Smrg} 679848b8605Smrg 680848b8605Smrg 681848b8605Smrg/** 682848b8605Smrg * New with GL_EXT_timer_query 683848b8605Smrg */ 684848b8605Smrgvoid GLAPIENTRY 685848b8605Smrg_mesa_GetQueryObjecti64v(GLuint id, GLenum pname, GLint64EXT *params) 686848b8605Smrg{ 687848b8605Smrg struct gl_query_object *q = NULL; 688848b8605Smrg GET_CURRENT_CONTEXT(ctx); 689848b8605Smrg 690848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 691848b8605Smrg _mesa_debug(ctx, "glGetQueryObjecti64v(%u, %s)\n", id, 692848b8605Smrg _mesa_lookup_enum_by_nr(pname)); 693848b8605Smrg 694848b8605Smrg if (id) 695848b8605Smrg q = _mesa_lookup_query_object(ctx, id); 696848b8605Smrg 697848b8605Smrg if (!q || q->Active) { 698848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 699848b8605Smrg "glGetQueryObjectui64vARB(id=%d is invalid or active)", id); 700848b8605Smrg return; 701848b8605Smrg } 702848b8605Smrg 703848b8605Smrg switch (pname) { 704848b8605Smrg case GL_QUERY_RESULT_ARB: 705848b8605Smrg if (!q->Ready) 706848b8605Smrg ctx->Driver.WaitQuery(ctx, q); 707848b8605Smrg *params = q->Result; 708848b8605Smrg break; 709848b8605Smrg case GL_QUERY_RESULT_AVAILABLE_ARB: 710848b8605Smrg if (!q->Ready) 711848b8605Smrg ctx->Driver.CheckQuery( ctx, q ); 712848b8605Smrg *params = q->Ready; 713848b8605Smrg break; 714848b8605Smrg default: 715848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjecti64vARB(pname)"); 716848b8605Smrg return; 717848b8605Smrg } 718848b8605Smrg} 719848b8605Smrg 720848b8605Smrg 721848b8605Smrg/** 722848b8605Smrg * New with GL_EXT_timer_query 723848b8605Smrg */ 724848b8605Smrgvoid GLAPIENTRY 725848b8605Smrg_mesa_GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64EXT *params) 726848b8605Smrg{ 727848b8605Smrg struct gl_query_object *q = NULL; 728848b8605Smrg GET_CURRENT_CONTEXT(ctx); 729848b8605Smrg 730848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 731848b8605Smrg _mesa_debug(ctx, "glGetQueryObjectui64v(%u, %s)\n", id, 732848b8605Smrg _mesa_lookup_enum_by_nr(pname)); 733848b8605Smrg 734848b8605Smrg if (id) 735848b8605Smrg q = _mesa_lookup_query_object(ctx, id); 736848b8605Smrg 737848b8605Smrg if (!q || q->Active) { 738848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 739848b8605Smrg "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id); 740848b8605Smrg return; 741848b8605Smrg } 742848b8605Smrg 743848b8605Smrg switch (pname) { 744848b8605Smrg case GL_QUERY_RESULT_ARB: 745848b8605Smrg if (!q->Ready) 746848b8605Smrg ctx->Driver.WaitQuery(ctx, q); 747848b8605Smrg *params = q->Result; 748848b8605Smrg break; 749848b8605Smrg case GL_QUERY_RESULT_AVAILABLE_ARB: 750848b8605Smrg if (!q->Ready) 751848b8605Smrg ctx->Driver.CheckQuery( ctx, q ); 752848b8605Smrg *params = q->Ready; 753848b8605Smrg break; 754848b8605Smrg default: 755848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectui64vARB(pname)"); 756848b8605Smrg return; 757848b8605Smrg } 758848b8605Smrg} 759848b8605Smrg 760848b8605Smrg/** 761848b8605Smrg * Allocate/init the context state related to query objects. 762848b8605Smrg */ 763848b8605Smrgvoid 764848b8605Smrg_mesa_init_queryobj(struct gl_context *ctx) 765848b8605Smrg{ 766848b8605Smrg ctx->Query.QueryObjects = _mesa_NewHashTable(); 767848b8605Smrg ctx->Query.CurrentOcclusionObject = NULL; 768848b8605Smrg 769848b8605Smrg ctx->Const.QueryCounterBits.SamplesPassed = 64; 770848b8605Smrg ctx->Const.QueryCounterBits.TimeElapsed = 64; 771848b8605Smrg ctx->Const.QueryCounterBits.Timestamp = 64; 772848b8605Smrg ctx->Const.QueryCounterBits.PrimitivesGenerated = 64; 773848b8605Smrg ctx->Const.QueryCounterBits.PrimitivesWritten = 64; 774848b8605Smrg} 775848b8605Smrg 776848b8605Smrg 777848b8605Smrg/** 778848b8605Smrg * Callback for deleting a query object. Called by _mesa_HashDeleteAll(). 779848b8605Smrg */ 780848b8605Smrgstatic void 781848b8605Smrgdelete_queryobj_cb(GLuint id, void *data, void *userData) 782848b8605Smrg{ 783848b8605Smrg struct gl_query_object *q= (struct gl_query_object *) data; 784848b8605Smrg struct gl_context *ctx = (struct gl_context *)userData; 785848b8605Smrg ctx->Driver.DeleteQuery(ctx, q); 786848b8605Smrg} 787848b8605Smrg 788848b8605Smrg 789848b8605Smrg/** 790848b8605Smrg * Free the context state related to query objects. 791848b8605Smrg */ 792848b8605Smrgvoid 793848b8605Smrg_mesa_free_queryobj_data(struct gl_context *ctx) 794848b8605Smrg{ 795848b8605Smrg _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx); 796848b8605Smrg _mesa_DeleteHashTable(ctx->Query.QueryObjects); 797848b8605Smrg} 798