queryobj.c revision af69d88d
17117f1b4Smrg/* 27117f1b4Smrg * Mesa 3-D graphics library 37117f1b4Smrg * 4c1f859d4Smrg * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 57117f1b4Smrg * 67117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 77117f1b4Smrg * copy of this software and associated documentation files (the "Software"), 87117f1b4Smrg * to deal in the Software without restriction, including without limitation 97117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 107117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the 117117f1b4Smrg * Software is furnished to do so, subject to the following conditions: 127117f1b4Smrg * 137117f1b4Smrg * The above copyright notice and this permission notice shall be included 147117f1b4Smrg * in all copies or substantial portions of the Software. 157117f1b4Smrg * 167117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 177117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 187117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE. 237117f1b4Smrg */ 247117f1b4Smrg 257117f1b4Smrg 267117f1b4Smrg#include "glheader.h" 277117f1b4Smrg#include "context.h" 283464ebd5Sriastradh#include "enums.h" 297117f1b4Smrg#include "hash.h" 307117f1b4Smrg#include "imports.h" 317117f1b4Smrg#include "queryobj.h" 327117f1b4Smrg#include "mtypes.h" 33cdc920a0Smrg#include "main/dispatch.h" 344a49301eSmrg 354a49301eSmrg 367117f1b4Smrg/** 377117f1b4Smrg * Allocate a new query object. This is a fallback routine called via 387117f1b4Smrg * ctx->Driver.NewQueryObject(). 397117f1b4Smrg * \param ctx - rendering context 407117f1b4Smrg * \param id - the new object's ID 417117f1b4Smrg * \return pointer to new query_object object or NULL if out of memory. 427117f1b4Smrg */ 434a49301eSmrgstatic struct gl_query_object * 443464ebd5Sriastradh_mesa_new_query_object(struct gl_context *ctx, GLuint id) 457117f1b4Smrg{ 46af69d88dSmrg struct gl_query_object *q = CALLOC_STRUCT(gl_query_object); 477117f1b4Smrg (void) ctx; 487117f1b4Smrg if (q) { 497117f1b4Smrg q->Id = id; 507117f1b4Smrg q->Result = 0; 517117f1b4Smrg q->Active = GL_FALSE; 52af69d88dSmrg 53af69d88dSmrg /* This is to satisfy the language of the specification: "In the initial 54af69d88dSmrg * state of a query object, the result is available" (OpenGL 3.1 § 55af69d88dSmrg * 2.13). 56af69d88dSmrg */ 57af69d88dSmrg q->Ready = GL_TRUE; 58af69d88dSmrg 59af69d88dSmrg /* OpenGL 3.1 § 2.13 says about GenQueries, "These names are marked as 60af69d88dSmrg * used, but no object is associated with them until the first time they 61af69d88dSmrg * are used by BeginQuery." Since our implementation actually does 62af69d88dSmrg * allocate an object at this point, use a flag to indicate that this 63af69d88dSmrg * object has not yet been bound so should not be considered a query. 64af69d88dSmrg */ 65af69d88dSmrg q->EverBound = GL_FALSE; 667117f1b4Smrg } 677117f1b4Smrg return q; 687117f1b4Smrg} 697117f1b4Smrg 707117f1b4Smrg 717117f1b4Smrg/** 72c1f859d4Smrg * Begin a query. Software driver fallback. 73c1f859d4Smrg * Called via ctx->Driver.BeginQuery(). 74c1f859d4Smrg */ 754a49301eSmrgstatic void 763464ebd5Sriastradh_mesa_begin_query(struct gl_context *ctx, struct gl_query_object *q) 77c1f859d4Smrg{ 78af69d88dSmrg ctx->NewState |= _NEW_DEPTH; /* for swrast */ 79c1f859d4Smrg} 80c1f859d4Smrg 81c1f859d4Smrg 82c1f859d4Smrg/** 83c1f859d4Smrg * End a query. Software driver fallback. 84c1f859d4Smrg * Called via ctx->Driver.EndQuery(). 85c1f859d4Smrg */ 864a49301eSmrgstatic void 873464ebd5Sriastradh_mesa_end_query(struct gl_context *ctx, struct gl_query_object *q) 88c1f859d4Smrg{ 89af69d88dSmrg ctx->NewState |= _NEW_DEPTH; /* for swrast */ 90c1f859d4Smrg q->Ready = GL_TRUE; 91c1f859d4Smrg} 92c1f859d4Smrg 93c1f859d4Smrg 94c1f859d4Smrg/** 95c1f859d4Smrg * Wait for query to complete. Software driver fallback. 96c1f859d4Smrg * Called via ctx->Driver.WaitQuery(). 97c1f859d4Smrg */ 984a49301eSmrgstatic void 993464ebd5Sriastradh_mesa_wait_query(struct gl_context *ctx, struct gl_query_object *q) 100c1f859d4Smrg{ 101c1f859d4Smrg /* For software drivers, _mesa_end_query() should have completed the query. 1024a49301eSmrg * For real hardware, implement a proper WaitQuery() driver function, 1034a49301eSmrg * which may require issuing a flush. 104c1f859d4Smrg */ 105c1f859d4Smrg assert(q->Ready); 106c1f859d4Smrg} 107c1f859d4Smrg 108c1f859d4Smrg 1094a49301eSmrg/** 1104a49301eSmrg * Check if a query results are ready. Software driver fallback. 1114a49301eSmrg * Called via ctx->Driver.CheckQuery(). 1124a49301eSmrg */ 1134a49301eSmrgstatic void 1143464ebd5Sriastradh_mesa_check_query(struct gl_context *ctx, struct gl_query_object *q) 1154a49301eSmrg{ 1164a49301eSmrg /* No-op for sw rendering. 1174a49301eSmrg * HW drivers may need to flush at this time. 1184a49301eSmrg */ 1194a49301eSmrg} 1204a49301eSmrg 1214a49301eSmrg 122c1f859d4Smrg/** 123c1f859d4Smrg * Delete a query object. Called via ctx->Driver.DeleteQuery(). 1247117f1b4Smrg * Not removed from hash table here. 1257117f1b4Smrg */ 1264a49301eSmrgstatic void 1273464ebd5Sriastradh_mesa_delete_query(struct gl_context *ctx, struct gl_query_object *q) 1287117f1b4Smrg{ 129af69d88dSmrg free(q->Label); 130cdc920a0Smrg free(q); 1317117f1b4Smrg} 1327117f1b4Smrg 1337117f1b4Smrg 1344a49301eSmrgvoid 1354a49301eSmrg_mesa_init_query_object_functions(struct dd_function_table *driver) 1364a49301eSmrg{ 1374a49301eSmrg driver->NewQueryObject = _mesa_new_query_object; 1384a49301eSmrg driver->DeleteQuery = _mesa_delete_query; 1394a49301eSmrg driver->BeginQuery = _mesa_begin_query; 1404a49301eSmrg driver->EndQuery = _mesa_end_query; 1414a49301eSmrg driver->WaitQuery = _mesa_wait_query; 1424a49301eSmrg driver->CheckQuery = _mesa_check_query; 1434a49301eSmrg} 1444a49301eSmrg 1454a49301eSmrg 1463464ebd5Sriastradh/** 147af69d88dSmrg * Return pointer to the query object binding point for the given target and 148af69d88dSmrg * index. 1493464ebd5Sriastradh * \return NULL if invalid target, else the address of binding point 1503464ebd5Sriastradh */ 1513464ebd5Sriastradhstatic struct gl_query_object ** 152af69d88dSmrgget_query_binding_point(struct gl_context *ctx, GLenum target, GLuint index) 1533464ebd5Sriastradh{ 1543464ebd5Sriastradh switch (target) { 1553464ebd5Sriastradh case GL_SAMPLES_PASSED_ARB: 1563464ebd5Sriastradh if (ctx->Extensions.ARB_occlusion_query) 1573464ebd5Sriastradh return &ctx->Query.CurrentOcclusionObject; 1583464ebd5Sriastradh else 1593464ebd5Sriastradh return NULL; 1603464ebd5Sriastradh case GL_ANY_SAMPLES_PASSED: 1613464ebd5Sriastradh if (ctx->Extensions.ARB_occlusion_query2) 1623464ebd5Sriastradh return &ctx->Query.CurrentOcclusionObject; 1633464ebd5Sriastradh else 1643464ebd5Sriastradh return NULL; 165af69d88dSmrg case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: 166af69d88dSmrg if (ctx->Extensions.ARB_ES3_compatibility 167af69d88dSmrg || (ctx->API == API_OPENGLES2 && ctx->Version >= 30)) 168af69d88dSmrg return &ctx->Query.CurrentOcclusionObject; 169af69d88dSmrg else 170af69d88dSmrg return NULL; 1713464ebd5Sriastradh case GL_TIME_ELAPSED_EXT: 1723464ebd5Sriastradh if (ctx->Extensions.EXT_timer_query) 1733464ebd5Sriastradh return &ctx->Query.CurrentTimerObject; 1743464ebd5Sriastradh else 1753464ebd5Sriastradh return NULL; 1763464ebd5Sriastradh case GL_PRIMITIVES_GENERATED: 1773464ebd5Sriastradh if (ctx->Extensions.EXT_transform_feedback) 178af69d88dSmrg return &ctx->Query.PrimitivesGenerated[index]; 1793464ebd5Sriastradh else 1803464ebd5Sriastradh return NULL; 1813464ebd5Sriastradh case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 1823464ebd5Sriastradh if (ctx->Extensions.EXT_transform_feedback) 183af69d88dSmrg return &ctx->Query.PrimitivesWritten[index]; 1843464ebd5Sriastradh else 1853464ebd5Sriastradh return NULL; 1863464ebd5Sriastradh default: 1873464ebd5Sriastradh return NULL; 1883464ebd5Sriastradh } 1893464ebd5Sriastradh} 1903464ebd5Sriastradh 1913464ebd5Sriastradh 192af69d88dSmrgvoid GLAPIENTRY 193af69d88dSmrg_mesa_GenQueries(GLsizei n, GLuint *ids) 1947117f1b4Smrg{ 1957117f1b4Smrg GLuint first; 1967117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 1977117f1b4Smrg 1983464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 1993464ebd5Sriastradh _mesa_debug(ctx, "glGenQueries(%d)\n", n); 2003464ebd5Sriastradh 2017117f1b4Smrg if (n < 0) { 2027117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glGenQueriesARB(n < 0)"); 2037117f1b4Smrg return; 2047117f1b4Smrg } 2057117f1b4Smrg 2067117f1b4Smrg first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n); 2077117f1b4Smrg if (first) { 2087117f1b4Smrg GLsizei i; 2097117f1b4Smrg for (i = 0; i < n; i++) { 2107117f1b4Smrg struct gl_query_object *q 2117117f1b4Smrg = ctx->Driver.NewQueryObject(ctx, first + i); 2127117f1b4Smrg if (!q) { 2137117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenQueriesARB"); 2147117f1b4Smrg return; 2157117f1b4Smrg } 2167117f1b4Smrg ids[i] = first + i; 2177117f1b4Smrg _mesa_HashInsert(ctx->Query.QueryObjects, first + i, q); 2187117f1b4Smrg } 2197117f1b4Smrg } 2207117f1b4Smrg} 2217117f1b4Smrg 2227117f1b4Smrg 223af69d88dSmrgvoid GLAPIENTRY 224af69d88dSmrg_mesa_DeleteQueries(GLsizei n, const GLuint *ids) 2257117f1b4Smrg{ 2267117f1b4Smrg GLint i; 2277117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 2283464ebd5Sriastradh FLUSH_VERTICES(ctx, 0); 2293464ebd5Sriastradh 2303464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 231af69d88dSmrg _mesa_debug(ctx, "glDeleteQueries(%d)\n", n); 2327117f1b4Smrg 2337117f1b4Smrg if (n < 0) { 2347117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)"); 2357117f1b4Smrg return; 2367117f1b4Smrg } 2377117f1b4Smrg 2387117f1b4Smrg for (i = 0; i < n; i++) { 2397117f1b4Smrg if (ids[i] > 0) { 240cdc920a0Smrg struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]); 2417117f1b4Smrg if (q) { 242af69d88dSmrg if (q->Active) { 243af69d88dSmrg struct gl_query_object **bindpt; 244af69d88dSmrg bindpt = get_query_binding_point(ctx, q->Target, q->Stream); 245af69d88dSmrg assert(bindpt); /* Should be non-null for active q. */ 246af69d88dSmrg if (bindpt) { 247af69d88dSmrg *bindpt = NULL; 248af69d88dSmrg } 249af69d88dSmrg q->Active = GL_FALSE; 250af69d88dSmrg ctx->Driver.EndQuery(ctx, q); 251af69d88dSmrg } 2527117f1b4Smrg _mesa_HashRemove(ctx->Query.QueryObjects, ids[i]); 253c1f859d4Smrg ctx->Driver.DeleteQuery(ctx, q); 2547117f1b4Smrg } 2557117f1b4Smrg } 2567117f1b4Smrg } 2577117f1b4Smrg} 2587117f1b4Smrg 2597117f1b4Smrg 260af69d88dSmrgGLboolean GLAPIENTRY 261af69d88dSmrg_mesa_IsQuery(GLuint id) 2627117f1b4Smrg{ 263af69d88dSmrg struct gl_query_object *q; 264af69d88dSmrg 2657117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 2667117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 2677117f1b4Smrg 2683464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 2693464ebd5Sriastradh _mesa_debug(ctx, "glIsQuery(%u)\n", id); 2703464ebd5Sriastradh 271af69d88dSmrg if (id == 0) 272af69d88dSmrg return GL_FALSE; 273af69d88dSmrg 274af69d88dSmrg q = _mesa_lookup_query_object(ctx, id); 275af69d88dSmrg if (q == NULL) 2767117f1b4Smrg return GL_FALSE; 277af69d88dSmrg 278af69d88dSmrg return q->EverBound; 2797117f1b4Smrg} 2807117f1b4Smrg 281af69d88dSmrgstatic GLboolean 282af69d88dSmrgquery_error_check_index(struct gl_context *ctx, GLenum target, GLuint index) 283af69d88dSmrg{ 284af69d88dSmrg switch (target) { 285af69d88dSmrg case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 286af69d88dSmrg case GL_PRIMITIVES_GENERATED: 287af69d88dSmrg if (index >= ctx->Const.MaxVertexStreams) { 288af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 289af69d88dSmrg "glBeginQueryIndexed(index>=MaxVertexStreams)"); 290af69d88dSmrg return GL_FALSE; 291af69d88dSmrg } 292af69d88dSmrg break; 293af69d88dSmrg default: 294af69d88dSmrg if (index > 0) { 295af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glBeginQueryIndexed(index>0)"); 296af69d88dSmrg return GL_FALSE; 297af69d88dSmrg } 298af69d88dSmrg } 299af69d88dSmrg return GL_TRUE; 300af69d88dSmrg} 3017117f1b4Smrg 302af69d88dSmrgvoid GLAPIENTRY 303af69d88dSmrg_mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id) 3047117f1b4Smrg{ 3053464ebd5Sriastradh struct gl_query_object *q, **bindpt; 3067117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 3077117f1b4Smrg 3083464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 309af69d88dSmrg _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n", 310af69d88dSmrg _mesa_lookup_enum_by_nr(target), index, id); 3113464ebd5Sriastradh 312af69d88dSmrg if (!query_error_check_index(ctx, target, index)) 313af69d88dSmrg return; 314af69d88dSmrg 315af69d88dSmrg FLUSH_VERTICES(ctx, 0); 3167117f1b4Smrg 317af69d88dSmrg bindpt = get_query_binding_point(ctx, target, index); 3183464ebd5Sriastradh if (!bindpt) { 319af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)"); 320af69d88dSmrg return; 321af69d88dSmrg } 322af69d88dSmrg 323af69d88dSmrg /* From the GL_ARB_occlusion_query spec: 324af69d88dSmrg * 325af69d88dSmrg * "If BeginQueryARB is called while another query is already in 326af69d88dSmrg * progress with the same target, an INVALID_OPERATION error is 327af69d88dSmrg * generated." 328af69d88dSmrg */ 329af69d88dSmrg if (*bindpt) { 330af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 331af69d88dSmrg "glBeginQuery{Indexed}(target=%s is active)", 332af69d88dSmrg _mesa_lookup_enum_by_nr(target)); 3333464ebd5Sriastradh return; 3347117f1b4Smrg } 3357117f1b4Smrg 3367117f1b4Smrg if (id == 0) { 337af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)"); 3387117f1b4Smrg return; 3397117f1b4Smrg } 3407117f1b4Smrg 341cdc920a0Smrg q = _mesa_lookup_query_object(ctx, id); 3427117f1b4Smrg if (!q) { 343af69d88dSmrg if (ctx->API != API_OPENGL_COMPAT) { 344af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 345af69d88dSmrg "glBeginQuery{Indexed}(non-gen name)"); 3467117f1b4Smrg return; 347af69d88dSmrg } else { 348af69d88dSmrg /* create new object */ 349af69d88dSmrg q = ctx->Driver.NewQueryObject(ctx, id); 350af69d88dSmrg if (!q) { 351af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}"); 352af69d88dSmrg return; 353af69d88dSmrg } 354af69d88dSmrg _mesa_HashInsert(ctx->Query.QueryObjects, id, q); 3557117f1b4Smrg } 3567117f1b4Smrg } 3577117f1b4Smrg else { 3587117f1b4Smrg /* pre-existing object */ 3597117f1b4Smrg if (q->Active) { 3607117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 361af69d88dSmrg "glBeginQuery{Indexed}(query already active)"); 3627117f1b4Smrg return; 3637117f1b4Smrg } 3647117f1b4Smrg } 3657117f1b4Smrg 366c1f859d4Smrg q->Target = target; 3677117f1b4Smrg q->Active = GL_TRUE; 3687117f1b4Smrg q->Result = 0; 3697117f1b4Smrg q->Ready = GL_FALSE; 370af69d88dSmrg q->EverBound = GL_TRUE; 371af69d88dSmrg q->Stream = index; 3727117f1b4Smrg 3733464ebd5Sriastradh /* XXX should probably refcount query objects */ 3743464ebd5Sriastradh *bindpt = q; 3757117f1b4Smrg 376c1f859d4Smrg ctx->Driver.BeginQuery(ctx, q); 3777117f1b4Smrg} 3787117f1b4Smrg 3797117f1b4Smrg 380af69d88dSmrgvoid GLAPIENTRY 381af69d88dSmrg_mesa_EndQueryIndexed(GLenum target, GLuint index) 3827117f1b4Smrg{ 3833464ebd5Sriastradh struct gl_query_object *q, **bindpt; 3847117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 3857117f1b4Smrg 3863464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 387af69d88dSmrg _mesa_debug(ctx, "glEndQueryIndexed(%s, %u)\n", 388af69d88dSmrg _mesa_lookup_enum_by_nr(target), index); 3893464ebd5Sriastradh 390af69d88dSmrg if (!query_error_check_index(ctx, target, index)) 391af69d88dSmrg return; 3927117f1b4Smrg 393af69d88dSmrg FLUSH_VERTICES(ctx, 0); 394af69d88dSmrg 395af69d88dSmrg bindpt = get_query_binding_point(ctx, target, index); 3963464ebd5Sriastradh if (!bindpt) { 397af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glEndQuery{Indexed}(target)"); 3983464ebd5Sriastradh return; 3997117f1b4Smrg } 4007117f1b4Smrg 4013464ebd5Sriastradh /* XXX should probably refcount query objects */ 4023464ebd5Sriastradh q = *bindpt; 403af69d88dSmrg 404af69d88dSmrg /* Check for GL_ANY_SAMPLES_PASSED vs GL_SAMPLES_PASSED. */ 405af69d88dSmrg if (q && q->Target != target) { 406af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 407af69d88dSmrg "glEndQuery(target=%s with active query of target %s)", 408af69d88dSmrg _mesa_lookup_enum_by_nr(target), 409af69d88dSmrg _mesa_lookup_enum_by_nr(q->Target)); 410af69d88dSmrg return; 411af69d88dSmrg } 412af69d88dSmrg 4133464ebd5Sriastradh *bindpt = NULL; 4143464ebd5Sriastradh 4157117f1b4Smrg if (!q || !q->Active) { 4167117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 417af69d88dSmrg "glEndQuery{Indexed}(no matching glBeginQuery{Indexed})"); 4187117f1b4Smrg return; 4197117f1b4Smrg } 4207117f1b4Smrg 4217117f1b4Smrg q->Active = GL_FALSE; 422c1f859d4Smrg ctx->Driver.EndQuery(ctx, q); 4237117f1b4Smrg} 4247117f1b4Smrg 425af69d88dSmrgvoid GLAPIENTRY 426af69d88dSmrg_mesa_BeginQuery(GLenum target, GLuint id) 427af69d88dSmrg{ 428af69d88dSmrg _mesa_BeginQueryIndexed(target, 0, id); 429af69d88dSmrg} 4307117f1b4Smrg 431af69d88dSmrgvoid GLAPIENTRY 432af69d88dSmrg_mesa_EndQuery(GLenum target) 4337117f1b4Smrg{ 434af69d88dSmrg _mesa_EndQueryIndexed(target, 0); 435af69d88dSmrg} 436af69d88dSmrg 437af69d88dSmrgvoid GLAPIENTRY 438af69d88dSmrg_mesa_QueryCounter(GLuint id, GLenum target) 439af69d88dSmrg{ 440af69d88dSmrg struct gl_query_object *q; 4417117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 4427117f1b4Smrg 4433464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 444af69d88dSmrg _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id, 445af69d88dSmrg _mesa_lookup_enum_by_nr(target)); 446af69d88dSmrg 447af69d88dSmrg /* error checking */ 448af69d88dSmrg if (target != GL_TIMESTAMP) { 449af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)"); 450af69d88dSmrg return; 451af69d88dSmrg } 452af69d88dSmrg 453af69d88dSmrg if (id == 0) { 454af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)"); 455af69d88dSmrg return; 456af69d88dSmrg } 457af69d88dSmrg 458af69d88dSmrg q = _mesa_lookup_query_object(ctx, id); 459af69d88dSmrg if (!q) { 460af69d88dSmrg /* XXX the Core profile should throw INVALID_OPERATION here */ 461af69d88dSmrg 462af69d88dSmrg /* create new object */ 463af69d88dSmrg q = ctx->Driver.NewQueryObject(ctx, id); 464af69d88dSmrg if (!q) { 465af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter"); 466af69d88dSmrg return; 467af69d88dSmrg } 468af69d88dSmrg _mesa_HashInsert(ctx->Query.QueryObjects, id, q); 469af69d88dSmrg } 470af69d88dSmrg else { 471af69d88dSmrg if (q->Target && q->Target != GL_TIMESTAMP) { 472af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 473af69d88dSmrg "glQueryCounter(id has an invalid target)"); 474af69d88dSmrg return; 475af69d88dSmrg } 476af69d88dSmrg } 477af69d88dSmrg 478af69d88dSmrg if (q->Active) { 479af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)"); 480af69d88dSmrg return; 481af69d88dSmrg } 482af69d88dSmrg 483af69d88dSmrg q->Target = target; 484af69d88dSmrg q->Result = 0; 485af69d88dSmrg q->Ready = GL_FALSE; 486af69d88dSmrg q->EverBound = GL_TRUE; 487af69d88dSmrg 488af69d88dSmrg if (ctx->Driver.QueryCounter) { 489af69d88dSmrg ctx->Driver.QueryCounter(ctx, q); 490af69d88dSmrg } else { 491af69d88dSmrg /* QueryCounter is implemented using EndQuery without BeginQuery 492af69d88dSmrg * in drivers. This is actually Direct3D and Gallium convention. 493af69d88dSmrg */ 494af69d88dSmrg ctx->Driver.EndQuery(ctx, q); 495af69d88dSmrg } 496af69d88dSmrg} 497af69d88dSmrg 498af69d88dSmrg 499af69d88dSmrgvoid GLAPIENTRY 500af69d88dSmrg_mesa_GetQueryIndexediv(GLenum target, GLuint index, GLenum pname, 501af69d88dSmrg GLint *params) 502af69d88dSmrg{ 503af69d88dSmrg struct gl_query_object *q = NULL, **bindpt = NULL; 504af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 505af69d88dSmrg 506af69d88dSmrg if (MESA_VERBOSE & VERBOSE_API) 507af69d88dSmrg _mesa_debug(ctx, "glGetQueryIndexediv(%s, %u, %s)\n", 5083464ebd5Sriastradh _mesa_lookup_enum_by_nr(target), 509af69d88dSmrg index, 5103464ebd5Sriastradh _mesa_lookup_enum_by_nr(pname)); 5113464ebd5Sriastradh 512af69d88dSmrg if (!query_error_check_index(ctx, target, index)) 5133464ebd5Sriastradh return; 514af69d88dSmrg 515af69d88dSmrg if (target == GL_TIMESTAMP) { 516af69d88dSmrg if (!ctx->Extensions.ARB_timer_query) { 517af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)"); 518af69d88dSmrg return; 519af69d88dSmrg } 5207117f1b4Smrg } 521af69d88dSmrg else { 522af69d88dSmrg bindpt = get_query_binding_point(ctx, target, index); 523af69d88dSmrg if (!bindpt) { 524af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(target)"); 525af69d88dSmrg return; 526af69d88dSmrg } 5277117f1b4Smrg 528af69d88dSmrg q = *bindpt; 529af69d88dSmrg } 5303464ebd5Sriastradh 5317117f1b4Smrg switch (pname) { 5327117f1b4Smrg case GL_QUERY_COUNTER_BITS_ARB: 533af69d88dSmrg switch (target) { 534af69d88dSmrg case GL_SAMPLES_PASSED: 535af69d88dSmrg *params = ctx->Const.QueryCounterBits.SamplesPassed; 536af69d88dSmrg break; 537af69d88dSmrg case GL_ANY_SAMPLES_PASSED: 538af69d88dSmrg /* The minimum value of this is 1 if it's nonzero, and the value 539af69d88dSmrg * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more 540af69d88dSmrg * bits. 541af69d88dSmrg */ 542af69d88dSmrg *params = 1; 543af69d88dSmrg break; 544af69d88dSmrg case GL_TIME_ELAPSED: 545af69d88dSmrg *params = ctx->Const.QueryCounterBits.TimeElapsed; 546af69d88dSmrg break; 547af69d88dSmrg case GL_TIMESTAMP: 548af69d88dSmrg *params = ctx->Const.QueryCounterBits.Timestamp; 549af69d88dSmrg break; 550af69d88dSmrg case GL_PRIMITIVES_GENERATED: 551af69d88dSmrg *params = ctx->Const.QueryCounterBits.PrimitivesGenerated; 552af69d88dSmrg break; 553af69d88dSmrg case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 554af69d88dSmrg *params = ctx->Const.QueryCounterBits.PrimitivesWritten; 555af69d88dSmrg break; 556af69d88dSmrg default: 557af69d88dSmrg _mesa_problem(ctx, 558af69d88dSmrg "Unknown target in glGetQueryIndexediv(target = %s)", 559af69d88dSmrg _mesa_lookup_enum_by_nr(target)); 560af69d88dSmrg *params = 0; 561af69d88dSmrg break; 562af69d88dSmrg } 5637117f1b4Smrg break; 5647117f1b4Smrg case GL_CURRENT_QUERY_ARB: 565af69d88dSmrg *params = (q && q->Target == target) ? q->Id : 0; 5667117f1b4Smrg break; 5677117f1b4Smrg default: 568af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(pname)"); 5697117f1b4Smrg return; 5707117f1b4Smrg } 5717117f1b4Smrg} 5727117f1b4Smrg 573af69d88dSmrgvoid GLAPIENTRY 574af69d88dSmrg_mesa_GetQueryiv(GLenum target, GLenum pname, GLint *params) 575af69d88dSmrg{ 576af69d88dSmrg _mesa_GetQueryIndexediv(target, 0, pname, params); 577af69d88dSmrg} 5787117f1b4Smrg 579af69d88dSmrgvoid GLAPIENTRY 580af69d88dSmrg_mesa_GetQueryObjectiv(GLuint id, GLenum pname, GLint *params) 5817117f1b4Smrg{ 5827117f1b4Smrg struct gl_query_object *q = NULL; 5837117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 5847117f1b4Smrg 5853464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 5863464ebd5Sriastradh _mesa_debug(ctx, "glGetQueryObjectiv(%u, %s)\n", id, 5873464ebd5Sriastradh _mesa_lookup_enum_by_nr(pname)); 5883464ebd5Sriastradh 5897117f1b4Smrg if (id) 590cdc920a0Smrg q = _mesa_lookup_query_object(ctx, id); 5917117f1b4Smrg 5927117f1b4Smrg if (!q || q->Active) { 5937117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 5947117f1b4Smrg "glGetQueryObjectivARB(id=%d is invalid or active)", id); 5957117f1b4Smrg return; 5967117f1b4Smrg } 5977117f1b4Smrg 5987117f1b4Smrg switch (pname) { 5997117f1b4Smrg case GL_QUERY_RESULT_ARB: 600c1f859d4Smrg if (!q->Ready) 601c1f859d4Smrg ctx->Driver.WaitQuery(ctx, q); 6027117f1b4Smrg /* if result is too large for returned type, clamp to max value */ 603af69d88dSmrg if (q->Target == GL_ANY_SAMPLES_PASSED 604af69d88dSmrg || q->Target == GL_ANY_SAMPLES_PASSED_CONSERVATIVE) { 6053464ebd5Sriastradh if (q->Result) 6063464ebd5Sriastradh *params = GL_TRUE; 6073464ebd5Sriastradh else 6083464ebd5Sriastradh *params = GL_FALSE; 6093464ebd5Sriastradh } else { 6103464ebd5Sriastradh if (q->Result > 0x7fffffff) { 6113464ebd5Sriastradh *params = 0x7fffffff; 6123464ebd5Sriastradh } 6133464ebd5Sriastradh else { 6143464ebd5Sriastradh *params = (GLint)q->Result; 6153464ebd5Sriastradh } 6167117f1b4Smrg } 6177117f1b4Smrg break; 6187117f1b4Smrg case GL_QUERY_RESULT_AVAILABLE_ARB: 619c1f859d4Smrg if (!q->Ready) 620c1f859d4Smrg ctx->Driver.CheckQuery( ctx, q ); 6217117f1b4Smrg *params = q->Ready; 6227117f1b4Smrg break; 6237117f1b4Smrg default: 6247117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)"); 6257117f1b4Smrg return; 6267117f1b4Smrg } 6277117f1b4Smrg} 6287117f1b4Smrg 6297117f1b4Smrg 630af69d88dSmrgvoid GLAPIENTRY 631af69d88dSmrg_mesa_GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params) 6327117f1b4Smrg{ 6337117f1b4Smrg struct gl_query_object *q = NULL; 6347117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 6357117f1b4Smrg 6363464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 6373464ebd5Sriastradh _mesa_debug(ctx, "glGetQueryObjectuiv(%u, %s)\n", id, 6383464ebd5Sriastradh _mesa_lookup_enum_by_nr(pname)); 6393464ebd5Sriastradh 6407117f1b4Smrg if (id) 641cdc920a0Smrg q = _mesa_lookup_query_object(ctx, id); 6427117f1b4Smrg 6437117f1b4Smrg if (!q || q->Active) { 6447117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 6457117f1b4Smrg "glGetQueryObjectuivARB(id=%d is invalid or active)", id); 6467117f1b4Smrg return; 6477117f1b4Smrg } 6487117f1b4Smrg 6497117f1b4Smrg switch (pname) { 6507117f1b4Smrg case GL_QUERY_RESULT_ARB: 651c1f859d4Smrg if (!q->Ready) 652c1f859d4Smrg ctx->Driver.WaitQuery(ctx, q); 6537117f1b4Smrg /* if result is too large for returned type, clamp to max value */ 654af69d88dSmrg if (q->Target == GL_ANY_SAMPLES_PASSED 655af69d88dSmrg || q->Target == GL_ANY_SAMPLES_PASSED_CONSERVATIVE) { 6563464ebd5Sriastradh if (q->Result) 6573464ebd5Sriastradh *params = GL_TRUE; 6583464ebd5Sriastradh else 6593464ebd5Sriastradh *params = GL_FALSE; 6603464ebd5Sriastradh } else { 6613464ebd5Sriastradh if (q->Result > 0xffffffff) { 6623464ebd5Sriastradh *params = 0xffffffff; 6633464ebd5Sriastradh } 6643464ebd5Sriastradh else { 6653464ebd5Sriastradh *params = (GLuint)q->Result; 6663464ebd5Sriastradh } 6677117f1b4Smrg } 6687117f1b4Smrg break; 6697117f1b4Smrg case GL_QUERY_RESULT_AVAILABLE_ARB: 670c1f859d4Smrg if (!q->Ready) 671c1f859d4Smrg ctx->Driver.CheckQuery( ctx, q ); 6727117f1b4Smrg *params = q->Ready; 6737117f1b4Smrg break; 6747117f1b4Smrg default: 6757117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)"); 6767117f1b4Smrg return; 6777117f1b4Smrg } 6787117f1b4Smrg} 6797117f1b4Smrg 6807117f1b4Smrg 6817117f1b4Smrg/** 6827117f1b4Smrg * New with GL_EXT_timer_query 6837117f1b4Smrg */ 684af69d88dSmrgvoid GLAPIENTRY 685af69d88dSmrg_mesa_GetQueryObjecti64v(GLuint id, GLenum pname, GLint64EXT *params) 6867117f1b4Smrg{ 6877117f1b4Smrg struct gl_query_object *q = NULL; 6887117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 6897117f1b4Smrg 6903464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 6913464ebd5Sriastradh _mesa_debug(ctx, "glGetQueryObjecti64v(%u, %s)\n", id, 6923464ebd5Sriastradh _mesa_lookup_enum_by_nr(pname)); 6933464ebd5Sriastradh 6947117f1b4Smrg if (id) 695cdc920a0Smrg q = _mesa_lookup_query_object(ctx, id); 6967117f1b4Smrg 6977117f1b4Smrg if (!q || q->Active) { 6987117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 6997117f1b4Smrg "glGetQueryObjectui64vARB(id=%d is invalid or active)", id); 7007117f1b4Smrg return; 7017117f1b4Smrg } 7027117f1b4Smrg 7037117f1b4Smrg switch (pname) { 7047117f1b4Smrg case GL_QUERY_RESULT_ARB: 705c1f859d4Smrg if (!q->Ready) 706c1f859d4Smrg ctx->Driver.WaitQuery(ctx, q); 7077117f1b4Smrg *params = q->Result; 7087117f1b4Smrg break; 7097117f1b4Smrg case GL_QUERY_RESULT_AVAILABLE_ARB: 710c1f859d4Smrg if (!q->Ready) 711c1f859d4Smrg ctx->Driver.CheckQuery( ctx, q ); 7127117f1b4Smrg *params = q->Ready; 7137117f1b4Smrg break; 7147117f1b4Smrg default: 7157117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjecti64vARB(pname)"); 7167117f1b4Smrg return; 7177117f1b4Smrg } 7187117f1b4Smrg} 7197117f1b4Smrg 7207117f1b4Smrg 7217117f1b4Smrg/** 7227117f1b4Smrg * New with GL_EXT_timer_query 7237117f1b4Smrg */ 724af69d88dSmrgvoid GLAPIENTRY 725af69d88dSmrg_mesa_GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64EXT *params) 7267117f1b4Smrg{ 7277117f1b4Smrg struct gl_query_object *q = NULL; 7287117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 7297117f1b4Smrg 7303464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 7313464ebd5Sriastradh _mesa_debug(ctx, "glGetQueryObjectui64v(%u, %s)\n", id, 7323464ebd5Sriastradh _mesa_lookup_enum_by_nr(pname)); 7333464ebd5Sriastradh 7347117f1b4Smrg if (id) 735cdc920a0Smrg q = _mesa_lookup_query_object(ctx, id); 7367117f1b4Smrg 7377117f1b4Smrg if (!q || q->Active) { 7387117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 7397117f1b4Smrg "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id); 7407117f1b4Smrg return; 7417117f1b4Smrg } 7427117f1b4Smrg 7437117f1b4Smrg switch (pname) { 7447117f1b4Smrg case GL_QUERY_RESULT_ARB: 745c1f859d4Smrg if (!q->Ready) 746c1f859d4Smrg ctx->Driver.WaitQuery(ctx, q); 7477117f1b4Smrg *params = q->Result; 7487117f1b4Smrg break; 7497117f1b4Smrg case GL_QUERY_RESULT_AVAILABLE_ARB: 750c1f859d4Smrg if (!q->Ready) 751c1f859d4Smrg ctx->Driver.CheckQuery( ctx, q ); 7527117f1b4Smrg *params = q->Ready; 7537117f1b4Smrg break; 7547117f1b4Smrg default: 7557117f1b4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectui64vARB(pname)"); 7567117f1b4Smrg return; 7577117f1b4Smrg } 7587117f1b4Smrg} 7597117f1b4Smrg 7607117f1b4Smrg/** 7617117f1b4Smrg * Allocate/init the context state related to query objects. 7627117f1b4Smrg */ 7637117f1b4Smrgvoid 7643464ebd5Sriastradh_mesa_init_queryobj(struct gl_context *ctx) 7657117f1b4Smrg{ 7667117f1b4Smrg ctx->Query.QueryObjects = _mesa_NewHashTable(); 7677117f1b4Smrg ctx->Query.CurrentOcclusionObject = NULL; 768af69d88dSmrg 769af69d88dSmrg ctx->Const.QueryCounterBits.SamplesPassed = 64; 770af69d88dSmrg ctx->Const.QueryCounterBits.TimeElapsed = 64; 771af69d88dSmrg ctx->Const.QueryCounterBits.Timestamp = 64; 772af69d88dSmrg ctx->Const.QueryCounterBits.PrimitivesGenerated = 64; 773af69d88dSmrg ctx->Const.QueryCounterBits.PrimitivesWritten = 64; 7747117f1b4Smrg} 7757117f1b4Smrg 7767117f1b4Smrg 7777117f1b4Smrg/** 7787117f1b4Smrg * Callback for deleting a query object. Called by _mesa_HashDeleteAll(). 7797117f1b4Smrg */ 7807117f1b4Smrgstatic void 7817117f1b4Smrgdelete_queryobj_cb(GLuint id, void *data, void *userData) 7827117f1b4Smrg{ 7837117f1b4Smrg struct gl_query_object *q= (struct gl_query_object *) data; 7843464ebd5Sriastradh struct gl_context *ctx = (struct gl_context *)userData; 785c1f859d4Smrg ctx->Driver.DeleteQuery(ctx, q); 7867117f1b4Smrg} 7877117f1b4Smrg 7887117f1b4Smrg 7897117f1b4Smrg/** 7907117f1b4Smrg * Free the context state related to query objects. 7917117f1b4Smrg */ 7927117f1b4Smrgvoid 7933464ebd5Sriastradh_mesa_free_queryobj_data(struct gl_context *ctx) 7947117f1b4Smrg{ 795c1f859d4Smrg _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx); 7967117f1b4Smrg _mesa_DeleteHashTable(ctx->Query.QueryObjects); 7977117f1b4Smrg} 798