queryobj.c revision b9abf16e
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 2601e04c3fSmrg#include "bufferobj.h" 277117f1b4Smrg#include "glheader.h" 287117f1b4Smrg#include "context.h" 293464ebd5Sriastradh#include "enums.h" 307117f1b4Smrg#include "hash.h" 317117f1b4Smrg#include "imports.h" 327117f1b4Smrg#include "queryobj.h" 337117f1b4Smrg#include "mtypes.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 14501e04c3fSmrgstatic struct gl_query_object ** 14601e04c3fSmrgget_pipe_stats_binding_point(struct gl_context *ctx, 14701e04c3fSmrg GLenum target) 14801e04c3fSmrg{ 149b9abf16eSmaya const int which = target - GL_VERTICES_SUBMITTED; 15001e04c3fSmrg assert(which < MAX_PIPELINE_STATISTICS); 15101e04c3fSmrg 152b9abf16eSmaya if (!_mesa_has_ARB_pipeline_statistics_query(ctx)) 15301e04c3fSmrg return NULL; 15401e04c3fSmrg 15501e04c3fSmrg return &ctx->Query.pipeline_stats[which]; 15601e04c3fSmrg} 1574a49301eSmrg 1583464ebd5Sriastradh/** 159af69d88dSmrg * Return pointer to the query object binding point for the given target and 160af69d88dSmrg * index. 1613464ebd5Sriastradh * \return NULL if invalid target, else the address of binding point 1623464ebd5Sriastradh */ 1633464ebd5Sriastradhstatic struct gl_query_object ** 164af69d88dSmrgget_query_binding_point(struct gl_context *ctx, GLenum target, GLuint index) 1653464ebd5Sriastradh{ 1663464ebd5Sriastradh switch (target) { 167b9abf16eSmaya case GL_SAMPLES_PASSED: 168b9abf16eSmaya if (_mesa_has_ARB_occlusion_query(ctx) || 169b9abf16eSmaya _mesa_has_ARB_occlusion_query2(ctx)) 1703464ebd5Sriastradh return &ctx->Query.CurrentOcclusionObject; 1713464ebd5Sriastradh else 1723464ebd5Sriastradh return NULL; 1733464ebd5Sriastradh case GL_ANY_SAMPLES_PASSED: 174b9abf16eSmaya if (_mesa_has_ARB_occlusion_query2(ctx) || 175b9abf16eSmaya _mesa_has_EXT_occlusion_query_boolean(ctx)) 1763464ebd5Sriastradh return &ctx->Query.CurrentOcclusionObject; 1773464ebd5Sriastradh else 1783464ebd5Sriastradh return NULL; 179af69d88dSmrg case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: 180b9abf16eSmaya if (_mesa_has_ARB_ES3_compatibility(ctx) || 181b9abf16eSmaya _mesa_has_EXT_occlusion_query_boolean(ctx)) 182af69d88dSmrg return &ctx->Query.CurrentOcclusionObject; 183af69d88dSmrg else 184af69d88dSmrg return NULL; 185b9abf16eSmaya case GL_TIME_ELAPSED: 186b9abf16eSmaya if (_mesa_has_EXT_timer_query(ctx) || 187b9abf16eSmaya _mesa_has_EXT_disjoint_timer_query(ctx)) 1883464ebd5Sriastradh return &ctx->Query.CurrentTimerObject; 1893464ebd5Sriastradh else 1903464ebd5Sriastradh return NULL; 1913464ebd5Sriastradh case GL_PRIMITIVES_GENERATED: 192b9abf16eSmaya if (_mesa_has_EXT_transform_feedback(ctx) || 193b9abf16eSmaya _mesa_has_EXT_tessellation_shader(ctx) || 194b9abf16eSmaya _mesa_has_OES_geometry_shader(ctx)) 195af69d88dSmrg return &ctx->Query.PrimitivesGenerated[index]; 1963464ebd5Sriastradh else 1973464ebd5Sriastradh return NULL; 1983464ebd5Sriastradh case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 199b9abf16eSmaya if (_mesa_has_EXT_transform_feedback(ctx) || _mesa_is_gles3(ctx)) 200af69d88dSmrg return &ctx->Query.PrimitivesWritten[index]; 2013464ebd5Sriastradh else 2023464ebd5Sriastradh return NULL; 203b9abf16eSmaya case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW: 204b9abf16eSmaya if (_mesa_has_ARB_transform_feedback_overflow_query(ctx)) 20501e04c3fSmrg return &ctx->Query.TransformFeedbackOverflow[index]; 20601e04c3fSmrg else 20701e04c3fSmrg return NULL; 208b9abf16eSmaya case GL_TRANSFORM_FEEDBACK_OVERFLOW: 209b9abf16eSmaya if (_mesa_has_ARB_transform_feedback_overflow_query(ctx)) 21001e04c3fSmrg return &ctx->Query.TransformFeedbackOverflowAny; 21101e04c3fSmrg else 21201e04c3fSmrg return NULL; 21301e04c3fSmrg 214b9abf16eSmaya case GL_VERTICES_SUBMITTED: 215b9abf16eSmaya case GL_PRIMITIVES_SUBMITTED: 216b9abf16eSmaya case GL_VERTEX_SHADER_INVOCATIONS: 217b9abf16eSmaya case GL_FRAGMENT_SHADER_INVOCATIONS: 218b9abf16eSmaya case GL_CLIPPING_INPUT_PRIMITIVES: 219b9abf16eSmaya case GL_CLIPPING_OUTPUT_PRIMITIVES: 22001e04c3fSmrg return get_pipe_stats_binding_point(ctx, target); 22101e04c3fSmrg 22201e04c3fSmrg case GL_GEOMETRY_SHADER_INVOCATIONS: 22301e04c3fSmrg /* GL_GEOMETRY_SHADER_INVOCATIONS is defined in a non-sequential order */ 224b9abf16eSmaya target = GL_VERTICES_SUBMITTED + MAX_PIPELINE_STATISTICS - 1; 22501e04c3fSmrg /* fallthrough */ 226b9abf16eSmaya case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED: 22701e04c3fSmrg if (_mesa_has_geometry_shaders(ctx)) 22801e04c3fSmrg return get_pipe_stats_binding_point(ctx, target); 22901e04c3fSmrg else 23001e04c3fSmrg return NULL; 23101e04c3fSmrg 232b9abf16eSmaya case GL_TESS_CONTROL_SHADER_PATCHES: 233b9abf16eSmaya case GL_TESS_EVALUATION_SHADER_INVOCATIONS: 23401e04c3fSmrg if (_mesa_has_tessellation(ctx)) 23501e04c3fSmrg return get_pipe_stats_binding_point(ctx, target); 23601e04c3fSmrg else 23701e04c3fSmrg return NULL; 23801e04c3fSmrg 239b9abf16eSmaya case GL_COMPUTE_SHADER_INVOCATIONS: 24001e04c3fSmrg if (_mesa_has_compute_shaders(ctx)) 24101e04c3fSmrg return get_pipe_stats_binding_point(ctx, target); 24201e04c3fSmrg else 24301e04c3fSmrg return NULL; 24401e04c3fSmrg 2453464ebd5Sriastradh default: 2463464ebd5Sriastradh return NULL; 2473464ebd5Sriastradh } 2483464ebd5Sriastradh} 2493464ebd5Sriastradh 25001e04c3fSmrg/** 25101e04c3fSmrg * Create $n query objects and store them in *ids. Make them of type $target 25201e04c3fSmrg * if dsa is set. Called from _mesa_GenQueries() and _mesa_CreateQueries(). 25301e04c3fSmrg */ 25401e04c3fSmrgstatic void 25501e04c3fSmrgcreate_queries(struct gl_context *ctx, GLenum target, GLsizei n, GLuint *ids, 25601e04c3fSmrg bool dsa) 2577117f1b4Smrg{ 25801e04c3fSmrg const char *func = dsa ? "glGenQueries" : "glCreateQueries"; 2597117f1b4Smrg GLuint first; 2607117f1b4Smrg 2613464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 26201e04c3fSmrg _mesa_debug(ctx, "%s(%d)\n", func, n); 2633464ebd5Sriastradh 2647117f1b4Smrg if (n < 0) { 26501e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func); 2667117f1b4Smrg return; 2677117f1b4Smrg } 2687117f1b4Smrg 2697117f1b4Smrg first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n); 2707117f1b4Smrg if (first) { 2717117f1b4Smrg GLsizei i; 2727117f1b4Smrg for (i = 0; i < n; i++) { 2737117f1b4Smrg struct gl_query_object *q 2747117f1b4Smrg = ctx->Driver.NewQueryObject(ctx, first + i); 2757117f1b4Smrg if (!q) { 27601e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); 2777117f1b4Smrg return; 27801e04c3fSmrg } else if (dsa) { 27901e04c3fSmrg /* Do the equivalent of binding the buffer with a target */ 28001e04c3fSmrg q->Target = target; 28101e04c3fSmrg q->EverBound = GL_TRUE; 2827117f1b4Smrg } 2837117f1b4Smrg ids[i] = first + i; 28401e04c3fSmrg _mesa_HashInsertLocked(ctx->Query.QueryObjects, first + i, q); 2857117f1b4Smrg } 2867117f1b4Smrg } 2877117f1b4Smrg} 2887117f1b4Smrg 28901e04c3fSmrgvoid GLAPIENTRY 29001e04c3fSmrg_mesa_GenQueries(GLsizei n, GLuint *ids) 29101e04c3fSmrg{ 29201e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 29301e04c3fSmrg create_queries(ctx, 0, n, ids, false); 29401e04c3fSmrg} 29501e04c3fSmrg 29601e04c3fSmrgvoid GLAPIENTRY 29701e04c3fSmrg_mesa_CreateQueries(GLenum target, GLsizei n, GLuint *ids) 29801e04c3fSmrg{ 29901e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 30001e04c3fSmrg 30101e04c3fSmrg switch (target) { 30201e04c3fSmrg case GL_SAMPLES_PASSED: 30301e04c3fSmrg case GL_ANY_SAMPLES_PASSED: 30401e04c3fSmrg case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: 30501e04c3fSmrg case GL_TIME_ELAPSED: 30601e04c3fSmrg case GL_TIMESTAMP: 30701e04c3fSmrg case GL_PRIMITIVES_GENERATED: 30801e04c3fSmrg case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 309b9abf16eSmaya case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW: 310b9abf16eSmaya case GL_TRANSFORM_FEEDBACK_OVERFLOW: 31101e04c3fSmrg break; 31201e04c3fSmrg default: 31301e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glCreateQueries(invalid target = %s)", 31401e04c3fSmrg _mesa_enum_to_string(target)); 31501e04c3fSmrg return; 31601e04c3fSmrg } 31701e04c3fSmrg 31801e04c3fSmrg create_queries(ctx, target, n, ids, true); 31901e04c3fSmrg} 32001e04c3fSmrg 3217117f1b4Smrg 322af69d88dSmrgvoid GLAPIENTRY 323af69d88dSmrg_mesa_DeleteQueries(GLsizei n, const GLuint *ids) 3247117f1b4Smrg{ 3257117f1b4Smrg GLint i; 3267117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 3273464ebd5Sriastradh FLUSH_VERTICES(ctx, 0); 3283464ebd5Sriastradh 3293464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 330af69d88dSmrg _mesa_debug(ctx, "glDeleteQueries(%d)\n", n); 3317117f1b4Smrg 3327117f1b4Smrg if (n < 0) { 3337117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)"); 3347117f1b4Smrg return; 3357117f1b4Smrg } 3367117f1b4Smrg 3377117f1b4Smrg for (i = 0; i < n; i++) { 3387117f1b4Smrg if (ids[i] > 0) { 339cdc920a0Smrg struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]); 3407117f1b4Smrg if (q) { 341af69d88dSmrg if (q->Active) { 342af69d88dSmrg struct gl_query_object **bindpt; 343af69d88dSmrg bindpt = get_query_binding_point(ctx, q->Target, q->Stream); 344af69d88dSmrg assert(bindpt); /* Should be non-null for active q. */ 345af69d88dSmrg if (bindpt) { 346af69d88dSmrg *bindpt = NULL; 347af69d88dSmrg } 348af69d88dSmrg q->Active = GL_FALSE; 349af69d88dSmrg ctx->Driver.EndQuery(ctx, q); 350af69d88dSmrg } 35101e04c3fSmrg _mesa_HashRemoveLocked(ctx->Query.QueryObjects, ids[i]); 352c1f859d4Smrg ctx->Driver.DeleteQuery(ctx, q); 3537117f1b4Smrg } 3547117f1b4Smrg } 3557117f1b4Smrg } 3567117f1b4Smrg} 3577117f1b4Smrg 3587117f1b4Smrg 359af69d88dSmrgGLboolean GLAPIENTRY 360af69d88dSmrg_mesa_IsQuery(GLuint id) 3617117f1b4Smrg{ 362af69d88dSmrg struct gl_query_object *q; 363af69d88dSmrg 3647117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 3657117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 3667117f1b4Smrg 3673464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 3683464ebd5Sriastradh _mesa_debug(ctx, "glIsQuery(%u)\n", id); 3693464ebd5Sriastradh 370af69d88dSmrg if (id == 0) 371af69d88dSmrg return GL_FALSE; 372af69d88dSmrg 373af69d88dSmrg q = _mesa_lookup_query_object(ctx, id); 374af69d88dSmrg if (q == NULL) 3757117f1b4Smrg return GL_FALSE; 376af69d88dSmrg 377af69d88dSmrg return q->EverBound; 3787117f1b4Smrg} 3797117f1b4Smrg 380af69d88dSmrgstatic GLboolean 381af69d88dSmrgquery_error_check_index(struct gl_context *ctx, GLenum target, GLuint index) 382af69d88dSmrg{ 383af69d88dSmrg switch (target) { 384af69d88dSmrg case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 385af69d88dSmrg case GL_PRIMITIVES_GENERATED: 386b9abf16eSmaya case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW: 387af69d88dSmrg if (index >= ctx->Const.MaxVertexStreams) { 388af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 389af69d88dSmrg "glBeginQueryIndexed(index>=MaxVertexStreams)"); 390af69d88dSmrg return GL_FALSE; 391af69d88dSmrg } 392af69d88dSmrg break; 393af69d88dSmrg default: 394af69d88dSmrg if (index > 0) { 395af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glBeginQueryIndexed(index>0)"); 396af69d88dSmrg return GL_FALSE; 397af69d88dSmrg } 398af69d88dSmrg } 399af69d88dSmrg return GL_TRUE; 400af69d88dSmrg} 4017117f1b4Smrg 402af69d88dSmrgvoid GLAPIENTRY 403af69d88dSmrg_mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id) 4047117f1b4Smrg{ 4053464ebd5Sriastradh struct gl_query_object *q, **bindpt; 4067117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 4077117f1b4Smrg 4083464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 409af69d88dSmrg _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n", 41001e04c3fSmrg _mesa_enum_to_string(target), index, id); 4113464ebd5Sriastradh 412af69d88dSmrg if (!query_error_check_index(ctx, target, index)) 413af69d88dSmrg return; 414af69d88dSmrg 415af69d88dSmrg FLUSH_VERTICES(ctx, 0); 4167117f1b4Smrg 417af69d88dSmrg bindpt = get_query_binding_point(ctx, target, index); 4183464ebd5Sriastradh if (!bindpt) { 419af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)"); 420af69d88dSmrg return; 421af69d88dSmrg } 422af69d88dSmrg 423af69d88dSmrg /* From the GL_ARB_occlusion_query spec: 424af69d88dSmrg * 425af69d88dSmrg * "If BeginQueryARB is called while another query is already in 426af69d88dSmrg * progress with the same target, an INVALID_OPERATION error is 427af69d88dSmrg * generated." 428af69d88dSmrg */ 429af69d88dSmrg if (*bindpt) { 430af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 431af69d88dSmrg "glBeginQuery{Indexed}(target=%s is active)", 43201e04c3fSmrg _mesa_enum_to_string(target)); 4333464ebd5Sriastradh return; 4347117f1b4Smrg } 4357117f1b4Smrg 4367117f1b4Smrg if (id == 0) { 437af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)"); 4387117f1b4Smrg return; 4397117f1b4Smrg } 4407117f1b4Smrg 441cdc920a0Smrg q = _mesa_lookup_query_object(ctx, id); 4427117f1b4Smrg if (!q) { 443af69d88dSmrg if (ctx->API != API_OPENGL_COMPAT) { 444af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 445af69d88dSmrg "glBeginQuery{Indexed}(non-gen name)"); 4467117f1b4Smrg return; 447af69d88dSmrg } else { 448af69d88dSmrg /* create new object */ 449af69d88dSmrg q = ctx->Driver.NewQueryObject(ctx, id); 450af69d88dSmrg if (!q) { 451af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}"); 452af69d88dSmrg return; 453af69d88dSmrg } 45401e04c3fSmrg _mesa_HashInsertLocked(ctx->Query.QueryObjects, id, q); 4557117f1b4Smrg } 4567117f1b4Smrg } 4577117f1b4Smrg else { 4587117f1b4Smrg /* pre-existing object */ 4597117f1b4Smrg if (q->Active) { 4607117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 461af69d88dSmrg "glBeginQuery{Indexed}(query already active)"); 4627117f1b4Smrg return; 4637117f1b4Smrg } 46401e04c3fSmrg 46501e04c3fSmrg /* Section 2.14 Asynchronous Queries, page 84 of the OpenGL ES 3.0.4 46601e04c3fSmrg * spec states: 46701e04c3fSmrg * 46801e04c3fSmrg * "BeginQuery generates an INVALID_OPERATION error if any of the 46901e04c3fSmrg * following conditions hold: [...] id is the name of an 47001e04c3fSmrg * existing query object whose type does not match target; [...] 47101e04c3fSmrg * 47201e04c3fSmrg * Similar wording exists in the OpenGL 4.5 spec, section 4.2. QUERY 47301e04c3fSmrg * OBJECTS AND ASYNCHRONOUS QUERIES, page 43. 47401e04c3fSmrg */ 47501e04c3fSmrg if (q->EverBound && q->Target != target) { 47601e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 47701e04c3fSmrg "glBeginQuery{Indexed}(target mismatch)"); 47801e04c3fSmrg return; 47901e04c3fSmrg } 4807117f1b4Smrg } 4817117f1b4Smrg 48201e04c3fSmrg /* This possibly changes the target of a buffer allocated by 48301e04c3fSmrg * CreateQueries. Issue 39) in the ARB_direct_state_access extension states 48401e04c3fSmrg * the following: 48501e04c3fSmrg * 48601e04c3fSmrg * "CreateQueries adds a <target>, so strictly speaking the <target> 48701e04c3fSmrg * command isn't needed for BeginQuery/EndQuery, but in the end, this also 48801e04c3fSmrg * isn't a selector, so we decided not to change it." 48901e04c3fSmrg * 49001e04c3fSmrg * Updating the target of the query object should be acceptable, so let's 49101e04c3fSmrg * do that. 49201e04c3fSmrg */ 49301e04c3fSmrg 494c1f859d4Smrg q->Target = target; 4957117f1b4Smrg q->Active = GL_TRUE; 4967117f1b4Smrg q->Result = 0; 4977117f1b4Smrg q->Ready = GL_FALSE; 498af69d88dSmrg q->EverBound = GL_TRUE; 499af69d88dSmrg q->Stream = index; 5007117f1b4Smrg 5013464ebd5Sriastradh /* XXX should probably refcount query objects */ 5023464ebd5Sriastradh *bindpt = q; 5037117f1b4Smrg 504c1f859d4Smrg ctx->Driver.BeginQuery(ctx, q); 5057117f1b4Smrg} 5067117f1b4Smrg 5077117f1b4Smrg 508af69d88dSmrgvoid GLAPIENTRY 509af69d88dSmrg_mesa_EndQueryIndexed(GLenum target, GLuint index) 5107117f1b4Smrg{ 5113464ebd5Sriastradh struct gl_query_object *q, **bindpt; 5127117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 5137117f1b4Smrg 5143464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 515af69d88dSmrg _mesa_debug(ctx, "glEndQueryIndexed(%s, %u)\n", 51601e04c3fSmrg _mesa_enum_to_string(target), index); 5173464ebd5Sriastradh 518af69d88dSmrg if (!query_error_check_index(ctx, target, index)) 519af69d88dSmrg return; 5207117f1b4Smrg 521af69d88dSmrg FLUSH_VERTICES(ctx, 0); 522af69d88dSmrg 523af69d88dSmrg bindpt = get_query_binding_point(ctx, target, index); 5243464ebd5Sriastradh if (!bindpt) { 525af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glEndQuery{Indexed}(target)"); 5263464ebd5Sriastradh return; 5277117f1b4Smrg } 5287117f1b4Smrg 5293464ebd5Sriastradh /* XXX should probably refcount query objects */ 5303464ebd5Sriastradh q = *bindpt; 531af69d88dSmrg 532af69d88dSmrg /* Check for GL_ANY_SAMPLES_PASSED vs GL_SAMPLES_PASSED. */ 533af69d88dSmrg if (q && q->Target != target) { 534af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 535af69d88dSmrg "glEndQuery(target=%s with active query of target %s)", 53601e04c3fSmrg _mesa_enum_to_string(target), 53701e04c3fSmrg _mesa_enum_to_string(q->Target)); 538af69d88dSmrg return; 539af69d88dSmrg } 540af69d88dSmrg 5413464ebd5Sriastradh *bindpt = NULL; 5423464ebd5Sriastradh 5437117f1b4Smrg if (!q || !q->Active) { 5447117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 545af69d88dSmrg "glEndQuery{Indexed}(no matching glBeginQuery{Indexed})"); 5467117f1b4Smrg return; 5477117f1b4Smrg } 5487117f1b4Smrg 5497117f1b4Smrg q->Active = GL_FALSE; 550c1f859d4Smrg ctx->Driver.EndQuery(ctx, q); 5517117f1b4Smrg} 5527117f1b4Smrg 553af69d88dSmrgvoid GLAPIENTRY 554af69d88dSmrg_mesa_BeginQuery(GLenum target, GLuint id) 555af69d88dSmrg{ 556af69d88dSmrg _mesa_BeginQueryIndexed(target, 0, id); 557af69d88dSmrg} 5587117f1b4Smrg 559af69d88dSmrgvoid GLAPIENTRY 560af69d88dSmrg_mesa_EndQuery(GLenum target) 5617117f1b4Smrg{ 562af69d88dSmrg _mesa_EndQueryIndexed(target, 0); 563af69d88dSmrg} 564af69d88dSmrg 565af69d88dSmrgvoid GLAPIENTRY 566af69d88dSmrg_mesa_QueryCounter(GLuint id, GLenum target) 567af69d88dSmrg{ 568af69d88dSmrg struct gl_query_object *q; 5697117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 5707117f1b4Smrg 5713464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 572af69d88dSmrg _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id, 57301e04c3fSmrg _mesa_enum_to_string(target)); 574af69d88dSmrg 575af69d88dSmrg /* error checking */ 576af69d88dSmrg if (target != GL_TIMESTAMP) { 577af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)"); 578af69d88dSmrg return; 579af69d88dSmrg } 580af69d88dSmrg 581af69d88dSmrg if (id == 0) { 582af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)"); 583af69d88dSmrg return; 584af69d88dSmrg } 585af69d88dSmrg 586af69d88dSmrg q = _mesa_lookup_query_object(ctx, id); 587af69d88dSmrg if (!q) { 588af69d88dSmrg /* XXX the Core profile should throw INVALID_OPERATION here */ 589af69d88dSmrg 590af69d88dSmrg /* create new object */ 591af69d88dSmrg q = ctx->Driver.NewQueryObject(ctx, id); 592af69d88dSmrg if (!q) { 593af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter"); 594af69d88dSmrg return; 595af69d88dSmrg } 59601e04c3fSmrg _mesa_HashInsertLocked(ctx->Query.QueryObjects, id, q); 597af69d88dSmrg } 598af69d88dSmrg else { 599af69d88dSmrg if (q->Target && q->Target != GL_TIMESTAMP) { 600af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 601af69d88dSmrg "glQueryCounter(id has an invalid target)"); 602af69d88dSmrg return; 603af69d88dSmrg } 604af69d88dSmrg } 605af69d88dSmrg 606af69d88dSmrg if (q->Active) { 607af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)"); 608af69d88dSmrg return; 609af69d88dSmrg } 610af69d88dSmrg 61101e04c3fSmrg /* This possibly changes the target of a buffer allocated by 61201e04c3fSmrg * CreateQueries. Issue 39) in the ARB_direct_state_access extension states 61301e04c3fSmrg * the following: 61401e04c3fSmrg * 61501e04c3fSmrg * "CreateQueries adds a <target>, so strictly speaking the <target> 61601e04c3fSmrg * command isn't needed for BeginQuery/EndQuery, but in the end, this also 61701e04c3fSmrg * isn't a selector, so we decided not to change it." 61801e04c3fSmrg * 61901e04c3fSmrg * Updating the target of the query object should be acceptable, so let's 62001e04c3fSmrg * do that. 62101e04c3fSmrg */ 62201e04c3fSmrg 623af69d88dSmrg q->Target = target; 624af69d88dSmrg q->Result = 0; 625af69d88dSmrg q->Ready = GL_FALSE; 626af69d88dSmrg q->EverBound = GL_TRUE; 627af69d88dSmrg 628af69d88dSmrg if (ctx->Driver.QueryCounter) { 629af69d88dSmrg ctx->Driver.QueryCounter(ctx, q); 630af69d88dSmrg } else { 631af69d88dSmrg /* QueryCounter is implemented using EndQuery without BeginQuery 632af69d88dSmrg * in drivers. This is actually Direct3D and Gallium convention. 633af69d88dSmrg */ 634af69d88dSmrg ctx->Driver.EndQuery(ctx, q); 635af69d88dSmrg } 636af69d88dSmrg} 637af69d88dSmrg 638af69d88dSmrg 639af69d88dSmrgvoid GLAPIENTRY 640af69d88dSmrg_mesa_GetQueryIndexediv(GLenum target, GLuint index, GLenum pname, 641af69d88dSmrg GLint *params) 642af69d88dSmrg{ 643af69d88dSmrg struct gl_query_object *q = NULL, **bindpt = NULL; 644af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 645af69d88dSmrg 646af69d88dSmrg if (MESA_VERBOSE & VERBOSE_API) 647af69d88dSmrg _mesa_debug(ctx, "glGetQueryIndexediv(%s, %u, %s)\n", 64801e04c3fSmrg _mesa_enum_to_string(target), 649af69d88dSmrg index, 65001e04c3fSmrg _mesa_enum_to_string(pname)); 6513464ebd5Sriastradh 652af69d88dSmrg if (!query_error_check_index(ctx, target, index)) 6533464ebd5Sriastradh return; 654af69d88dSmrg 65501e04c3fSmrg /* From the GL_EXT_occlusion_query_boolean spec: 65601e04c3fSmrg * 65701e04c3fSmrg * "The error INVALID_ENUM is generated if GetQueryivEXT is called where 65801e04c3fSmrg * <pname> is not CURRENT_QUERY_EXT." 65901e04c3fSmrg * 66001e04c3fSmrg * Same rule is present also in ES 3.2 spec. 66101e04c3fSmrg */ 66201e04c3fSmrg if (_mesa_is_gles(ctx) && pname != GL_CURRENT_QUERY) { 66301e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivEXT(%s)", 66401e04c3fSmrg _mesa_enum_to_string(pname)); 66501e04c3fSmrg return; 66601e04c3fSmrg } 66701e04c3fSmrg 668af69d88dSmrg if (target == GL_TIMESTAMP) { 669b9abf16eSmaya if (!_mesa_has_ARB_timer_query(ctx) && 670b9abf16eSmaya !_mesa_has_EXT_disjoint_timer_query(ctx)) { 671af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)"); 672af69d88dSmrg return; 673af69d88dSmrg } 6747117f1b4Smrg } 675af69d88dSmrg else { 676af69d88dSmrg bindpt = get_query_binding_point(ctx, target, index); 677af69d88dSmrg if (!bindpt) { 678af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(target)"); 679af69d88dSmrg return; 680af69d88dSmrg } 6817117f1b4Smrg 682af69d88dSmrg q = *bindpt; 683af69d88dSmrg } 6843464ebd5Sriastradh 6857117f1b4Smrg switch (pname) { 686b9abf16eSmaya case GL_QUERY_COUNTER_BITS: 687af69d88dSmrg switch (target) { 688af69d88dSmrg case GL_SAMPLES_PASSED: 689af69d88dSmrg *params = ctx->Const.QueryCounterBits.SamplesPassed; 690af69d88dSmrg break; 691af69d88dSmrg case GL_ANY_SAMPLES_PASSED: 69201e04c3fSmrg case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: 693af69d88dSmrg /* The minimum value of this is 1 if it's nonzero, and the value 694af69d88dSmrg * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more 695af69d88dSmrg * bits. 696af69d88dSmrg */ 697af69d88dSmrg *params = 1; 698af69d88dSmrg break; 699af69d88dSmrg case GL_TIME_ELAPSED: 700af69d88dSmrg *params = ctx->Const.QueryCounterBits.TimeElapsed; 701af69d88dSmrg break; 702af69d88dSmrg case GL_TIMESTAMP: 703af69d88dSmrg *params = ctx->Const.QueryCounterBits.Timestamp; 704af69d88dSmrg break; 705af69d88dSmrg case GL_PRIMITIVES_GENERATED: 706af69d88dSmrg *params = ctx->Const.QueryCounterBits.PrimitivesGenerated; 707af69d88dSmrg break; 708af69d88dSmrg case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 709af69d88dSmrg *params = ctx->Const.QueryCounterBits.PrimitivesWritten; 710af69d88dSmrg break; 711b9abf16eSmaya case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW: 712b9abf16eSmaya case GL_TRANSFORM_FEEDBACK_OVERFLOW: 71301e04c3fSmrg /* The minimum value of this is 1 if it's nonzero, and the value 71401e04c3fSmrg * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more 71501e04c3fSmrg * bits. 71601e04c3fSmrg */ 71701e04c3fSmrg *params = 1; 71801e04c3fSmrg break; 719b9abf16eSmaya case GL_VERTICES_SUBMITTED: 72001e04c3fSmrg *params = ctx->Const.QueryCounterBits.VerticesSubmitted; 72101e04c3fSmrg break; 722b9abf16eSmaya case GL_PRIMITIVES_SUBMITTED: 72301e04c3fSmrg *params = ctx->Const.QueryCounterBits.PrimitivesSubmitted; 72401e04c3fSmrg break; 725b9abf16eSmaya case GL_VERTEX_SHADER_INVOCATIONS: 72601e04c3fSmrg *params = ctx->Const.QueryCounterBits.VsInvocations; 72701e04c3fSmrg break; 728b9abf16eSmaya case GL_TESS_CONTROL_SHADER_PATCHES: 72901e04c3fSmrg *params = ctx->Const.QueryCounterBits.TessPatches; 73001e04c3fSmrg break; 731b9abf16eSmaya case GL_TESS_EVALUATION_SHADER_INVOCATIONS: 73201e04c3fSmrg *params = ctx->Const.QueryCounterBits.TessInvocations; 73301e04c3fSmrg break; 73401e04c3fSmrg case GL_GEOMETRY_SHADER_INVOCATIONS: 73501e04c3fSmrg *params = ctx->Const.QueryCounterBits.GsInvocations; 73601e04c3fSmrg break; 737b9abf16eSmaya case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED: 73801e04c3fSmrg *params = ctx->Const.QueryCounterBits.GsPrimitives; 73901e04c3fSmrg break; 740b9abf16eSmaya case GL_FRAGMENT_SHADER_INVOCATIONS: 74101e04c3fSmrg *params = ctx->Const.QueryCounterBits.FsInvocations; 74201e04c3fSmrg break; 743b9abf16eSmaya case GL_COMPUTE_SHADER_INVOCATIONS: 74401e04c3fSmrg *params = ctx->Const.QueryCounterBits.ComputeInvocations; 74501e04c3fSmrg break; 746b9abf16eSmaya case GL_CLIPPING_INPUT_PRIMITIVES: 74701e04c3fSmrg *params = ctx->Const.QueryCounterBits.ClInPrimitives; 74801e04c3fSmrg break; 749b9abf16eSmaya case GL_CLIPPING_OUTPUT_PRIMITIVES: 75001e04c3fSmrg *params = ctx->Const.QueryCounterBits.ClOutPrimitives; 75101e04c3fSmrg break; 752af69d88dSmrg default: 753af69d88dSmrg _mesa_problem(ctx, 754af69d88dSmrg "Unknown target in glGetQueryIndexediv(target = %s)", 75501e04c3fSmrg _mesa_enum_to_string(target)); 756af69d88dSmrg *params = 0; 757af69d88dSmrg break; 758af69d88dSmrg } 7597117f1b4Smrg break; 760b9abf16eSmaya case GL_CURRENT_QUERY: 761af69d88dSmrg *params = (q && q->Target == target) ? q->Id : 0; 7627117f1b4Smrg break; 7637117f1b4Smrg default: 764af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(pname)"); 7657117f1b4Smrg return; 7667117f1b4Smrg } 7677117f1b4Smrg} 7687117f1b4Smrg 769af69d88dSmrgvoid GLAPIENTRY 770af69d88dSmrg_mesa_GetQueryiv(GLenum target, GLenum pname, GLint *params) 771af69d88dSmrg{ 772af69d88dSmrg _mesa_GetQueryIndexediv(target, 0, pname, params); 773af69d88dSmrg} 7747117f1b4Smrg 77501e04c3fSmrgstatic void 77601e04c3fSmrgget_query_object(struct gl_context *ctx, const char *func, 77701e04c3fSmrg GLuint id, GLenum pname, GLenum ptype, 77801e04c3fSmrg struct gl_buffer_object *buf, intptr_t offset) 7797117f1b4Smrg{ 7807117f1b4Smrg struct gl_query_object *q = NULL; 78101e04c3fSmrg uint64_t value; 7827117f1b4Smrg 7833464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 78401e04c3fSmrg _mesa_debug(ctx, "%s(%u, %s)\n", func, id, 78501e04c3fSmrg _mesa_enum_to_string(pname)); 7863464ebd5Sriastradh 7877117f1b4Smrg if (id) 788cdc920a0Smrg q = _mesa_lookup_query_object(ctx, id); 7897117f1b4Smrg 79001e04c3fSmrg if (!q || q->Active || !q->EverBound) { 7917117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 79201e04c3fSmrg "%s(id=%d is invalid or active)", func, id); 79301e04c3fSmrg return; 79401e04c3fSmrg } 79501e04c3fSmrg 79601e04c3fSmrg /* From GL_EXT_occlusion_query_boolean spec: 79701e04c3fSmrg * 79801e04c3fSmrg * "Accepted by the <pname> parameter of GetQueryObjectivEXT and 79901e04c3fSmrg * GetQueryObjectuivEXT: 80001e04c3fSmrg * 80101e04c3fSmrg * QUERY_RESULT_EXT 0x8866 80201e04c3fSmrg * QUERY_RESULT_AVAILABLE_EXT 0x8867" 80301e04c3fSmrg * 80401e04c3fSmrg * Same rule is present also in ES 3.2 spec. 80501e04c3fSmrg */ 80601e04c3fSmrg if (_mesa_is_gles(ctx) && 80701e04c3fSmrg (pname != GL_QUERY_RESULT && pname != GL_QUERY_RESULT_AVAILABLE)) { 80801e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(%s)", func, 80901e04c3fSmrg _mesa_enum_to_string(pname)); 8107117f1b4Smrg return; 8117117f1b4Smrg } 8127117f1b4Smrg 81301e04c3fSmrg if (buf && buf != ctx->Shared->NullBufferObj) { 81401e04c3fSmrg bool is_64bit = ptype == GL_INT64_ARB || 81501e04c3fSmrg ptype == GL_UNSIGNED_INT64_ARB; 816b9abf16eSmaya if (!_mesa_has_ARB_query_buffer_object(ctx)) { 81701e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(not supported)", func); 81801e04c3fSmrg return; 81901e04c3fSmrg } 82001e04c3fSmrg if (buf->Size < offset + 4 * (is_64bit ? 2 : 1)) { 82101e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(out of bounds)", func); 82201e04c3fSmrg return; 82301e04c3fSmrg } 82401e04c3fSmrg 82501e04c3fSmrg if (offset < 0) { 82601e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset is negative)", func); 82701e04c3fSmrg return; 82801e04c3fSmrg } 82901e04c3fSmrg 83001e04c3fSmrg switch (pname) { 83101e04c3fSmrg case GL_QUERY_RESULT: 83201e04c3fSmrg case GL_QUERY_RESULT_NO_WAIT: 83301e04c3fSmrg case GL_QUERY_RESULT_AVAILABLE: 83401e04c3fSmrg case GL_QUERY_TARGET: 83501e04c3fSmrg ctx->Driver.StoreQueryResult(ctx, q, buf, offset, pname, ptype); 83601e04c3fSmrg return; 83701e04c3fSmrg } 83801e04c3fSmrg 83901e04c3fSmrg /* fall through to get error below */ 84001e04c3fSmrg } 84101e04c3fSmrg 8427117f1b4Smrg switch (pname) { 84301e04c3fSmrg case GL_QUERY_RESULT: 84401e04c3fSmrg if (!q->Ready) 84501e04c3fSmrg ctx->Driver.WaitQuery(ctx, q); 84601e04c3fSmrg value = q->Result; 84701e04c3fSmrg break; 84801e04c3fSmrg case GL_QUERY_RESULT_NO_WAIT: 849b9abf16eSmaya if (!_mesa_has_ARB_query_buffer_object(ctx)) 85001e04c3fSmrg goto invalid_enum; 85101e04c3fSmrg ctx->Driver.CheckQuery(ctx, q); 85201e04c3fSmrg if (!q->Ready) 8537117f1b4Smrg return; 85401e04c3fSmrg value = q->Result; 85501e04c3fSmrg break; 85601e04c3fSmrg case GL_QUERY_RESULT_AVAILABLE: 85701e04c3fSmrg if (!q->Ready) 85801e04c3fSmrg ctx->Driver.CheckQuery(ctx, q); 85901e04c3fSmrg value = q->Ready; 86001e04c3fSmrg break; 86101e04c3fSmrg case GL_QUERY_TARGET: 86201e04c3fSmrg value = q->Target; 86301e04c3fSmrg break; 86401e04c3fSmrg default: 86501e04c3fSmrginvalid_enum: 86601e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=%s)", 86701e04c3fSmrg func, _mesa_enum_to_string(pname)); 86801e04c3fSmrg return; 86901e04c3fSmrg } 87001e04c3fSmrg 87101e04c3fSmrg switch (ptype) { 87201e04c3fSmrg case GL_INT: { 87301e04c3fSmrg GLint *param = (GLint *)offset; 87401e04c3fSmrg if (value > 0x7fffffff) 87501e04c3fSmrg *param = 0x7fffffff; 87601e04c3fSmrg else 87701e04c3fSmrg *param = value; 87801e04c3fSmrg break; 87901e04c3fSmrg } 88001e04c3fSmrg case GL_UNSIGNED_INT: { 88101e04c3fSmrg GLuint *param = (GLuint *)offset; 88201e04c3fSmrg if (value > 0xffffffff) 88301e04c3fSmrg *param = 0xffffffff; 88401e04c3fSmrg else 88501e04c3fSmrg *param = value; 88601e04c3fSmrg break; 88701e04c3fSmrg } 88801e04c3fSmrg case GL_INT64_ARB: 88901e04c3fSmrg case GL_UNSIGNED_INT64_ARB: { 89001e04c3fSmrg GLuint64EXT *param = (GLuint64EXT *)offset; 89101e04c3fSmrg *param = value; 89201e04c3fSmrg break; 8937117f1b4Smrg } 89401e04c3fSmrg default: 89501e04c3fSmrg unreachable("unexpected ptype"); 89601e04c3fSmrg } 89701e04c3fSmrg} 89801e04c3fSmrg 89901e04c3fSmrgvoid GLAPIENTRY 90001e04c3fSmrg_mesa_GetQueryObjectiv(GLuint id, GLenum pname, GLint *params) 90101e04c3fSmrg{ 90201e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 90301e04c3fSmrg 90401e04c3fSmrg get_query_object(ctx, "glGetQueryObjectiv", 90501e04c3fSmrg id, pname, GL_INT, ctx->QueryBuffer, (intptr_t)params); 9067117f1b4Smrg} 9077117f1b4Smrg 9087117f1b4Smrg 909af69d88dSmrgvoid GLAPIENTRY 910af69d88dSmrg_mesa_GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params) 9117117f1b4Smrg{ 9127117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 9137117f1b4Smrg 91401e04c3fSmrg get_query_object(ctx, "glGetQueryObjectuiv", 91501e04c3fSmrg id, pname, GL_UNSIGNED_INT, 91601e04c3fSmrg ctx->QueryBuffer, (intptr_t)params); 91701e04c3fSmrg} 9183464ebd5Sriastradh 9197117f1b4Smrg 92001e04c3fSmrg/** 92101e04c3fSmrg * New with GL_EXT_timer_query 92201e04c3fSmrg */ 92301e04c3fSmrgvoid GLAPIENTRY 92401e04c3fSmrg_mesa_GetQueryObjecti64v(GLuint id, GLenum pname, GLint64EXT *params) 92501e04c3fSmrg{ 92601e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 9277117f1b4Smrg 92801e04c3fSmrg get_query_object(ctx, "glGetQueryObjecti64v", 92901e04c3fSmrg id, pname, GL_INT64_ARB, 93001e04c3fSmrg ctx->QueryBuffer, (intptr_t)params); 9317117f1b4Smrg} 9327117f1b4Smrg 9337117f1b4Smrg 9347117f1b4Smrg/** 9357117f1b4Smrg * New with GL_EXT_timer_query 9367117f1b4Smrg */ 937af69d88dSmrgvoid GLAPIENTRY 93801e04c3fSmrg_mesa_GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64EXT *params) 9397117f1b4Smrg{ 9407117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 9417117f1b4Smrg 94201e04c3fSmrg get_query_object(ctx, "glGetQueryObjectui64v", 94301e04c3fSmrg id, pname, GL_UNSIGNED_INT64_ARB, 94401e04c3fSmrg ctx->QueryBuffer, (intptr_t)params); 94501e04c3fSmrg} 9463464ebd5Sriastradh 94701e04c3fSmrg/** 94801e04c3fSmrg * New with GL_ARB_query_buffer_object 94901e04c3fSmrg */ 95001e04c3fSmrgvoid GLAPIENTRY 95101e04c3fSmrg_mesa_GetQueryBufferObjectiv(GLuint id, GLuint buffer, GLenum pname, 95201e04c3fSmrg GLintptr offset) 95301e04c3fSmrg{ 95401e04c3fSmrg struct gl_buffer_object *buf; 95501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 9567117f1b4Smrg 95701e04c3fSmrg buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectiv"); 95801e04c3fSmrg if (!buf) 9597117f1b4Smrg return; 9607117f1b4Smrg 96101e04c3fSmrg get_query_object(ctx, "glGetQueryBufferObjectiv", 96201e04c3fSmrg id, pname, GL_INT, buf, offset); 9637117f1b4Smrg} 9647117f1b4Smrg 9657117f1b4Smrg 966af69d88dSmrgvoid GLAPIENTRY 96701e04c3fSmrg_mesa_GetQueryBufferObjectuiv(GLuint id, GLuint buffer, GLenum pname, 96801e04c3fSmrg GLintptr offset) 9697117f1b4Smrg{ 97001e04c3fSmrg struct gl_buffer_object *buf; 9717117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 9727117f1b4Smrg 97301e04c3fSmrg buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectuiv"); 97401e04c3fSmrg if (!buf) 97501e04c3fSmrg return; 9763464ebd5Sriastradh 97701e04c3fSmrg get_query_object(ctx, "glGetQueryBufferObjectuiv", 97801e04c3fSmrg id, pname, GL_UNSIGNED_INT, buf, offset); 97901e04c3fSmrg} 9807117f1b4Smrg 98101e04c3fSmrg 98201e04c3fSmrgvoid GLAPIENTRY 98301e04c3fSmrg_mesa_GetQueryBufferObjecti64v(GLuint id, GLuint buffer, GLenum pname, 98401e04c3fSmrg GLintptr offset) 98501e04c3fSmrg{ 98601e04c3fSmrg struct gl_buffer_object *buf; 98701e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 98801e04c3fSmrg 98901e04c3fSmrg buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjecti64v"); 99001e04c3fSmrg if (!buf) 9917117f1b4Smrg return; 9927117f1b4Smrg 99301e04c3fSmrg get_query_object(ctx, "glGetQueryBufferObjecti64v", 99401e04c3fSmrg id, pname, GL_INT64_ARB, buf, offset); 9957117f1b4Smrg} 9967117f1b4Smrg 99701e04c3fSmrg 99801e04c3fSmrgvoid GLAPIENTRY 99901e04c3fSmrg_mesa_GetQueryBufferObjectui64v(GLuint id, GLuint buffer, GLenum pname, 100001e04c3fSmrg GLintptr offset) 100101e04c3fSmrg{ 100201e04c3fSmrg struct gl_buffer_object *buf; 100301e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 100401e04c3fSmrg 100501e04c3fSmrg buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectui64v"); 100601e04c3fSmrg if (!buf) 100701e04c3fSmrg return; 100801e04c3fSmrg 100901e04c3fSmrg get_query_object(ctx, "glGetQueryBufferObjectui64v", 101001e04c3fSmrg id, pname, GL_UNSIGNED_INT64_ARB, buf, offset); 101101e04c3fSmrg} 101201e04c3fSmrg 101301e04c3fSmrg 10147117f1b4Smrg/** 10157117f1b4Smrg * Allocate/init the context state related to query objects. 10167117f1b4Smrg */ 10177117f1b4Smrgvoid 10183464ebd5Sriastradh_mesa_init_queryobj(struct gl_context *ctx) 10197117f1b4Smrg{ 10207117f1b4Smrg ctx->Query.QueryObjects = _mesa_NewHashTable(); 10217117f1b4Smrg ctx->Query.CurrentOcclusionObject = NULL; 1022af69d88dSmrg 1023af69d88dSmrg ctx->Const.QueryCounterBits.SamplesPassed = 64; 1024af69d88dSmrg ctx->Const.QueryCounterBits.TimeElapsed = 64; 1025af69d88dSmrg ctx->Const.QueryCounterBits.Timestamp = 64; 1026af69d88dSmrg ctx->Const.QueryCounterBits.PrimitivesGenerated = 64; 1027af69d88dSmrg ctx->Const.QueryCounterBits.PrimitivesWritten = 64; 102801e04c3fSmrg 102901e04c3fSmrg ctx->Const.QueryCounterBits.VerticesSubmitted = 64; 103001e04c3fSmrg ctx->Const.QueryCounterBits.PrimitivesSubmitted = 64; 103101e04c3fSmrg ctx->Const.QueryCounterBits.VsInvocations = 64; 103201e04c3fSmrg ctx->Const.QueryCounterBits.TessPatches = 64; 103301e04c3fSmrg ctx->Const.QueryCounterBits.TessInvocations = 64; 103401e04c3fSmrg ctx->Const.QueryCounterBits.GsInvocations = 64; 103501e04c3fSmrg ctx->Const.QueryCounterBits.GsPrimitives = 64; 103601e04c3fSmrg ctx->Const.QueryCounterBits.FsInvocations = 64; 103701e04c3fSmrg ctx->Const.QueryCounterBits.ComputeInvocations = 64; 103801e04c3fSmrg ctx->Const.QueryCounterBits.ClInPrimitives = 64; 103901e04c3fSmrg ctx->Const.QueryCounterBits.ClOutPrimitives = 64; 10407117f1b4Smrg} 10417117f1b4Smrg 10427117f1b4Smrg 10437117f1b4Smrg/** 10447117f1b4Smrg * Callback for deleting a query object. Called by _mesa_HashDeleteAll(). 10457117f1b4Smrg */ 10467117f1b4Smrgstatic void 10477117f1b4Smrgdelete_queryobj_cb(GLuint id, void *data, void *userData) 10487117f1b4Smrg{ 10497117f1b4Smrg struct gl_query_object *q= (struct gl_query_object *) data; 10503464ebd5Sriastradh struct gl_context *ctx = (struct gl_context *)userData; 1051c1f859d4Smrg ctx->Driver.DeleteQuery(ctx, q); 10527117f1b4Smrg} 10537117f1b4Smrg 10547117f1b4Smrg 10557117f1b4Smrg/** 10567117f1b4Smrg * Free the context state related to query objects. 10577117f1b4Smrg */ 10587117f1b4Smrgvoid 10593464ebd5Sriastradh_mesa_free_queryobj_data(struct gl_context *ctx) 10607117f1b4Smrg{ 1061c1f859d4Smrg _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx); 10627117f1b4Smrg _mesa_DeleteHashTable(ctx->Query.QueryObjects); 10637117f1b4Smrg} 1064