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" 317ec681f3Smrg 327117f1b4Smrg#include "queryobj.h" 337117f1b4Smrg#include "mtypes.h" 347ec681f3Smrg#include "util/u_memory.h" 354a49301eSmrg 364a49301eSmrg 377117f1b4Smrg/** 387117f1b4Smrg * Allocate a new query object. This is a fallback routine called via 397117f1b4Smrg * ctx->Driver.NewQueryObject(). 407117f1b4Smrg * \param ctx - rendering context 417117f1b4Smrg * \param id - the new object's ID 427117f1b4Smrg * \return pointer to new query_object object or NULL if out of memory. 437117f1b4Smrg */ 444a49301eSmrgstatic struct gl_query_object * 453464ebd5Sriastradh_mesa_new_query_object(struct gl_context *ctx, GLuint id) 467117f1b4Smrg{ 47af69d88dSmrg struct gl_query_object *q = CALLOC_STRUCT(gl_query_object); 487117f1b4Smrg (void) ctx; 497117f1b4Smrg if (q) { 507117f1b4Smrg q->Id = id; 517117f1b4Smrg q->Result = 0; 527117f1b4Smrg q->Active = GL_FALSE; 53af69d88dSmrg 54af69d88dSmrg /* This is to satisfy the language of the specification: "In the initial 55af69d88dSmrg * state of a query object, the result is available" (OpenGL 3.1 § 56af69d88dSmrg * 2.13). 57af69d88dSmrg */ 58af69d88dSmrg q->Ready = GL_TRUE; 59af69d88dSmrg 60af69d88dSmrg /* OpenGL 3.1 § 2.13 says about GenQueries, "These names are marked as 61af69d88dSmrg * used, but no object is associated with them until the first time they 62af69d88dSmrg * are used by BeginQuery." Since our implementation actually does 63af69d88dSmrg * allocate an object at this point, use a flag to indicate that this 64af69d88dSmrg * object has not yet been bound so should not be considered a query. 65af69d88dSmrg */ 66af69d88dSmrg q->EverBound = GL_FALSE; 677117f1b4Smrg } 687117f1b4Smrg return q; 697117f1b4Smrg} 707117f1b4Smrg 717117f1b4Smrg 727117f1b4Smrg/** 73c1f859d4Smrg * Begin a query. Software driver fallback. 74c1f859d4Smrg * Called via ctx->Driver.BeginQuery(). 75c1f859d4Smrg */ 764a49301eSmrgstatic void 773464ebd5Sriastradh_mesa_begin_query(struct gl_context *ctx, struct gl_query_object *q) 78c1f859d4Smrg{ 79af69d88dSmrg ctx->NewState |= _NEW_DEPTH; /* for swrast */ 80c1f859d4Smrg} 81c1f859d4Smrg 82c1f859d4Smrg 83c1f859d4Smrg/** 84c1f859d4Smrg * End a query. Software driver fallback. 85c1f859d4Smrg * Called via ctx->Driver.EndQuery(). 86c1f859d4Smrg */ 874a49301eSmrgstatic void 883464ebd5Sriastradh_mesa_end_query(struct gl_context *ctx, struct gl_query_object *q) 89c1f859d4Smrg{ 90af69d88dSmrg ctx->NewState |= _NEW_DEPTH; /* for swrast */ 91c1f859d4Smrg q->Ready = GL_TRUE; 92c1f859d4Smrg} 93c1f859d4Smrg 94c1f859d4Smrg 95c1f859d4Smrg/** 96c1f859d4Smrg * Wait for query to complete. Software driver fallback. 97c1f859d4Smrg * Called via ctx->Driver.WaitQuery(). 98c1f859d4Smrg */ 994a49301eSmrgstatic void 1003464ebd5Sriastradh_mesa_wait_query(struct gl_context *ctx, struct gl_query_object *q) 101c1f859d4Smrg{ 102c1f859d4Smrg /* For software drivers, _mesa_end_query() should have completed the query. 1034a49301eSmrg * For real hardware, implement a proper WaitQuery() driver function, 1044a49301eSmrg * which may require issuing a flush. 105c1f859d4Smrg */ 106c1f859d4Smrg assert(q->Ready); 107c1f859d4Smrg} 108c1f859d4Smrg 109c1f859d4Smrg 1104a49301eSmrg/** 1114a49301eSmrg * Check if a query results are ready. Software driver fallback. 1124a49301eSmrg * Called via ctx->Driver.CheckQuery(). 1134a49301eSmrg */ 1144a49301eSmrgstatic void 1153464ebd5Sriastradh_mesa_check_query(struct gl_context *ctx, struct gl_query_object *q) 1164a49301eSmrg{ 1174a49301eSmrg /* No-op for sw rendering. 1184a49301eSmrg * HW drivers may need to flush at this time. 1194a49301eSmrg */ 1204a49301eSmrg} 1214a49301eSmrg 1224a49301eSmrg 123c1f859d4Smrg/** 1247ec681f3Smrg * Delete a query object. Called via ctx->Driver.DeleteQuery(), if not 1257ec681f3Smrg * overwritten by driver. In the latter case, called from the driver 1267ec681f3Smrg * after all driver-specific clean-up has been done. 1277117f1b4Smrg * Not removed from hash table here. 1287ec681f3Smrg * 1297ec681f3Smrg * \param ctx GL context to wich query object belongs. 1307ec681f3Smrg * \param q query object due to be deleted. 1317117f1b4Smrg */ 1327ec681f3Smrgvoid 1333464ebd5Sriastradh_mesa_delete_query(struct gl_context *ctx, struct gl_query_object *q) 1347117f1b4Smrg{ 135af69d88dSmrg free(q->Label); 136cdc920a0Smrg free(q); 1377117f1b4Smrg} 1387117f1b4Smrg 1397117f1b4Smrg 1404a49301eSmrgvoid 1414a49301eSmrg_mesa_init_query_object_functions(struct dd_function_table *driver) 1424a49301eSmrg{ 1434a49301eSmrg driver->NewQueryObject = _mesa_new_query_object; 1444a49301eSmrg driver->DeleteQuery = _mesa_delete_query; 1454a49301eSmrg driver->BeginQuery = _mesa_begin_query; 1464a49301eSmrg driver->EndQuery = _mesa_end_query; 1474a49301eSmrg driver->WaitQuery = _mesa_wait_query; 1484a49301eSmrg driver->CheckQuery = _mesa_check_query; 1494a49301eSmrg} 1504a49301eSmrg 15101e04c3fSmrgstatic struct gl_query_object ** 15201e04c3fSmrgget_pipe_stats_binding_point(struct gl_context *ctx, 15301e04c3fSmrg GLenum target) 15401e04c3fSmrg{ 155b9abf16eSmaya const int which = target - GL_VERTICES_SUBMITTED; 15601e04c3fSmrg assert(which < MAX_PIPELINE_STATISTICS); 15701e04c3fSmrg 158b9abf16eSmaya if (!_mesa_has_ARB_pipeline_statistics_query(ctx)) 15901e04c3fSmrg return NULL; 16001e04c3fSmrg 16101e04c3fSmrg return &ctx->Query.pipeline_stats[which]; 16201e04c3fSmrg} 1634a49301eSmrg 1643464ebd5Sriastradh/** 165af69d88dSmrg * Return pointer to the query object binding point for the given target and 166af69d88dSmrg * index. 1673464ebd5Sriastradh * \return NULL if invalid target, else the address of binding point 1683464ebd5Sriastradh */ 1693464ebd5Sriastradhstatic struct gl_query_object ** 170af69d88dSmrgget_query_binding_point(struct gl_context *ctx, GLenum target, GLuint index) 1713464ebd5Sriastradh{ 1723464ebd5Sriastradh switch (target) { 173b9abf16eSmaya case GL_SAMPLES_PASSED: 174b9abf16eSmaya if (_mesa_has_ARB_occlusion_query(ctx) || 175b9abf16eSmaya _mesa_has_ARB_occlusion_query2(ctx)) 1763464ebd5Sriastradh return &ctx->Query.CurrentOcclusionObject; 1773464ebd5Sriastradh else 1783464ebd5Sriastradh return NULL; 1793464ebd5Sriastradh case GL_ANY_SAMPLES_PASSED: 180b9abf16eSmaya if (_mesa_has_ARB_occlusion_query2(ctx) || 181b9abf16eSmaya _mesa_has_EXT_occlusion_query_boolean(ctx)) 1823464ebd5Sriastradh return &ctx->Query.CurrentOcclusionObject; 1833464ebd5Sriastradh else 1843464ebd5Sriastradh return NULL; 185af69d88dSmrg case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: 186b9abf16eSmaya if (_mesa_has_ARB_ES3_compatibility(ctx) || 187b9abf16eSmaya _mesa_has_EXT_occlusion_query_boolean(ctx)) 188af69d88dSmrg return &ctx->Query.CurrentOcclusionObject; 189af69d88dSmrg else 190af69d88dSmrg return NULL; 191b9abf16eSmaya case GL_TIME_ELAPSED: 192b9abf16eSmaya if (_mesa_has_EXT_timer_query(ctx) || 193b9abf16eSmaya _mesa_has_EXT_disjoint_timer_query(ctx)) 1943464ebd5Sriastradh return &ctx->Query.CurrentTimerObject; 1953464ebd5Sriastradh else 1963464ebd5Sriastradh return NULL; 1973464ebd5Sriastradh case GL_PRIMITIVES_GENERATED: 198b9abf16eSmaya if (_mesa_has_EXT_transform_feedback(ctx) || 199b9abf16eSmaya _mesa_has_EXT_tessellation_shader(ctx) || 200b9abf16eSmaya _mesa_has_OES_geometry_shader(ctx)) 201af69d88dSmrg return &ctx->Query.PrimitivesGenerated[index]; 2023464ebd5Sriastradh else 2033464ebd5Sriastradh return NULL; 2043464ebd5Sriastradh case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 205b9abf16eSmaya if (_mesa_has_EXT_transform_feedback(ctx) || _mesa_is_gles3(ctx)) 206af69d88dSmrg return &ctx->Query.PrimitivesWritten[index]; 2073464ebd5Sriastradh else 2083464ebd5Sriastradh return NULL; 209b9abf16eSmaya case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW: 210b9abf16eSmaya if (_mesa_has_ARB_transform_feedback_overflow_query(ctx)) 21101e04c3fSmrg return &ctx->Query.TransformFeedbackOverflow[index]; 21201e04c3fSmrg else 21301e04c3fSmrg return NULL; 214b9abf16eSmaya case GL_TRANSFORM_FEEDBACK_OVERFLOW: 215b9abf16eSmaya if (_mesa_has_ARB_transform_feedback_overflow_query(ctx)) 21601e04c3fSmrg return &ctx->Query.TransformFeedbackOverflowAny; 21701e04c3fSmrg else 21801e04c3fSmrg return NULL; 21901e04c3fSmrg 220b9abf16eSmaya case GL_VERTICES_SUBMITTED: 221b9abf16eSmaya case GL_PRIMITIVES_SUBMITTED: 222b9abf16eSmaya case GL_VERTEX_SHADER_INVOCATIONS: 223b9abf16eSmaya case GL_FRAGMENT_SHADER_INVOCATIONS: 224b9abf16eSmaya case GL_CLIPPING_INPUT_PRIMITIVES: 225b9abf16eSmaya case GL_CLIPPING_OUTPUT_PRIMITIVES: 22601e04c3fSmrg return get_pipe_stats_binding_point(ctx, target); 22701e04c3fSmrg 22801e04c3fSmrg case GL_GEOMETRY_SHADER_INVOCATIONS: 22901e04c3fSmrg /* GL_GEOMETRY_SHADER_INVOCATIONS is defined in a non-sequential order */ 230b9abf16eSmaya target = GL_VERTICES_SUBMITTED + MAX_PIPELINE_STATISTICS - 1; 2317ec681f3Smrg FALLTHROUGH; 232b9abf16eSmaya case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED: 23301e04c3fSmrg if (_mesa_has_geometry_shaders(ctx)) 23401e04c3fSmrg return get_pipe_stats_binding_point(ctx, target); 23501e04c3fSmrg else 23601e04c3fSmrg return NULL; 23701e04c3fSmrg 238b9abf16eSmaya case GL_TESS_CONTROL_SHADER_PATCHES: 239b9abf16eSmaya case GL_TESS_EVALUATION_SHADER_INVOCATIONS: 24001e04c3fSmrg if (_mesa_has_tessellation(ctx)) 24101e04c3fSmrg return get_pipe_stats_binding_point(ctx, target); 24201e04c3fSmrg else 24301e04c3fSmrg return NULL; 24401e04c3fSmrg 245b9abf16eSmaya case GL_COMPUTE_SHADER_INVOCATIONS: 24601e04c3fSmrg if (_mesa_has_compute_shaders(ctx)) 24701e04c3fSmrg return get_pipe_stats_binding_point(ctx, target); 24801e04c3fSmrg else 24901e04c3fSmrg return NULL; 25001e04c3fSmrg 2513464ebd5Sriastradh default: 2523464ebd5Sriastradh return NULL; 2533464ebd5Sriastradh } 2543464ebd5Sriastradh} 2553464ebd5Sriastradh 25601e04c3fSmrg/** 25701e04c3fSmrg * Create $n query objects and store them in *ids. Make them of type $target 25801e04c3fSmrg * if dsa is set. Called from _mesa_GenQueries() and _mesa_CreateQueries(). 25901e04c3fSmrg */ 26001e04c3fSmrgstatic void 26101e04c3fSmrgcreate_queries(struct gl_context *ctx, GLenum target, GLsizei n, GLuint *ids, 26201e04c3fSmrg bool dsa) 2637117f1b4Smrg{ 26401e04c3fSmrg const char *func = dsa ? "glGenQueries" : "glCreateQueries"; 2657117f1b4Smrg 2663464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 26701e04c3fSmrg _mesa_debug(ctx, "%s(%d)\n", func, n); 2683464ebd5Sriastradh 2697117f1b4Smrg if (n < 0) { 27001e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func); 2717117f1b4Smrg return; 2727117f1b4Smrg } 2737117f1b4Smrg 2747ec681f3Smrg if (_mesa_HashFindFreeKeys(ctx->Query.QueryObjects, ids, n)) { 2757117f1b4Smrg GLsizei i; 2767117f1b4Smrg for (i = 0; i < n; i++) { 2777117f1b4Smrg struct gl_query_object *q 2787ec681f3Smrg = ctx->Driver.NewQueryObject(ctx, ids[i]); 2797117f1b4Smrg if (!q) { 28001e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); 2817117f1b4Smrg return; 28201e04c3fSmrg } else if (dsa) { 28301e04c3fSmrg /* Do the equivalent of binding the buffer with a target */ 28401e04c3fSmrg q->Target = target; 28501e04c3fSmrg q->EverBound = GL_TRUE; 2867117f1b4Smrg } 2877ec681f3Smrg _mesa_HashInsertLocked(ctx->Query.QueryObjects, ids[i], q, true); 2887117f1b4Smrg } 2897117f1b4Smrg } 2907117f1b4Smrg} 2917117f1b4Smrg 29201e04c3fSmrgvoid GLAPIENTRY 29301e04c3fSmrg_mesa_GenQueries(GLsizei n, GLuint *ids) 29401e04c3fSmrg{ 29501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 29601e04c3fSmrg create_queries(ctx, 0, n, ids, false); 29701e04c3fSmrg} 29801e04c3fSmrg 29901e04c3fSmrgvoid GLAPIENTRY 30001e04c3fSmrg_mesa_CreateQueries(GLenum target, GLsizei n, GLuint *ids) 30101e04c3fSmrg{ 30201e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 30301e04c3fSmrg 30401e04c3fSmrg switch (target) { 30501e04c3fSmrg case GL_SAMPLES_PASSED: 30601e04c3fSmrg case GL_ANY_SAMPLES_PASSED: 30701e04c3fSmrg case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: 30801e04c3fSmrg case GL_TIME_ELAPSED: 30901e04c3fSmrg case GL_TIMESTAMP: 31001e04c3fSmrg case GL_PRIMITIVES_GENERATED: 31101e04c3fSmrg case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 312b9abf16eSmaya case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW: 313b9abf16eSmaya case GL_TRANSFORM_FEEDBACK_OVERFLOW: 31401e04c3fSmrg break; 31501e04c3fSmrg default: 31601e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glCreateQueries(invalid target = %s)", 31701e04c3fSmrg _mesa_enum_to_string(target)); 31801e04c3fSmrg return; 31901e04c3fSmrg } 32001e04c3fSmrg 32101e04c3fSmrg create_queries(ctx, target, n, ids, true); 32201e04c3fSmrg} 32301e04c3fSmrg 3247117f1b4Smrg 325af69d88dSmrgvoid GLAPIENTRY 326af69d88dSmrg_mesa_DeleteQueries(GLsizei n, const GLuint *ids) 3277117f1b4Smrg{ 3287117f1b4Smrg GLint i; 3297117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 3307ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 3313464ebd5Sriastradh 3323464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 333af69d88dSmrg _mesa_debug(ctx, "glDeleteQueries(%d)\n", n); 3347117f1b4Smrg 3357117f1b4Smrg if (n < 0) { 3367117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)"); 3377117f1b4Smrg return; 3387117f1b4Smrg } 3397117f1b4Smrg 3407117f1b4Smrg for (i = 0; i < n; i++) { 3417117f1b4Smrg if (ids[i] > 0) { 342cdc920a0Smrg struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]); 3437117f1b4Smrg if (q) { 344af69d88dSmrg if (q->Active) { 345af69d88dSmrg struct gl_query_object **bindpt; 346af69d88dSmrg bindpt = get_query_binding_point(ctx, q->Target, q->Stream); 347af69d88dSmrg assert(bindpt); /* Should be non-null for active q. */ 348af69d88dSmrg if (bindpt) { 349af69d88dSmrg *bindpt = NULL; 350af69d88dSmrg } 351af69d88dSmrg q->Active = GL_FALSE; 352af69d88dSmrg ctx->Driver.EndQuery(ctx, q); 353af69d88dSmrg } 35401e04c3fSmrg _mesa_HashRemoveLocked(ctx->Query.QueryObjects, ids[i]); 355c1f859d4Smrg ctx->Driver.DeleteQuery(ctx, q); 3567117f1b4Smrg } 3577117f1b4Smrg } 3587117f1b4Smrg } 3597117f1b4Smrg} 3607117f1b4Smrg 3617117f1b4Smrg 362af69d88dSmrgGLboolean GLAPIENTRY 363af69d88dSmrg_mesa_IsQuery(GLuint id) 3647117f1b4Smrg{ 365af69d88dSmrg struct gl_query_object *q; 366af69d88dSmrg 3677117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 3687117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 3697117f1b4Smrg 3703464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 3713464ebd5Sriastradh _mesa_debug(ctx, "glIsQuery(%u)\n", id); 3723464ebd5Sriastradh 373af69d88dSmrg if (id == 0) 374af69d88dSmrg return GL_FALSE; 375af69d88dSmrg 376af69d88dSmrg q = _mesa_lookup_query_object(ctx, id); 377af69d88dSmrg if (q == NULL) 3787117f1b4Smrg return GL_FALSE; 379af69d88dSmrg 380af69d88dSmrg return q->EverBound; 3817117f1b4Smrg} 3827117f1b4Smrg 383af69d88dSmrgstatic GLboolean 384af69d88dSmrgquery_error_check_index(struct gl_context *ctx, GLenum target, GLuint index) 385af69d88dSmrg{ 386af69d88dSmrg switch (target) { 387af69d88dSmrg case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 388af69d88dSmrg case GL_PRIMITIVES_GENERATED: 389b9abf16eSmaya case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW: 390af69d88dSmrg if (index >= ctx->Const.MaxVertexStreams) { 391af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 392af69d88dSmrg "glBeginQueryIndexed(index>=MaxVertexStreams)"); 393af69d88dSmrg return GL_FALSE; 394af69d88dSmrg } 395af69d88dSmrg break; 396af69d88dSmrg default: 397af69d88dSmrg if (index > 0) { 398af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glBeginQueryIndexed(index>0)"); 399af69d88dSmrg return GL_FALSE; 400af69d88dSmrg } 401af69d88dSmrg } 402af69d88dSmrg return GL_TRUE; 403af69d88dSmrg} 4047117f1b4Smrg 405af69d88dSmrgvoid GLAPIENTRY 406af69d88dSmrg_mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id) 4077117f1b4Smrg{ 4083464ebd5Sriastradh struct gl_query_object *q, **bindpt; 4097117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 4107117f1b4Smrg 4113464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 412af69d88dSmrg _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n", 41301e04c3fSmrg _mesa_enum_to_string(target), index, id); 4143464ebd5Sriastradh 415af69d88dSmrg if (!query_error_check_index(ctx, target, index)) 416af69d88dSmrg return; 417af69d88dSmrg 4187ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 4197117f1b4Smrg 420af69d88dSmrg bindpt = get_query_binding_point(ctx, target, index); 4213464ebd5Sriastradh if (!bindpt) { 422af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)"); 423af69d88dSmrg return; 424af69d88dSmrg } 425af69d88dSmrg 426af69d88dSmrg /* From the GL_ARB_occlusion_query spec: 427af69d88dSmrg * 428af69d88dSmrg * "If BeginQueryARB is called while another query is already in 429af69d88dSmrg * progress with the same target, an INVALID_OPERATION error is 430af69d88dSmrg * generated." 431af69d88dSmrg */ 432af69d88dSmrg if (*bindpt) { 433af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 434af69d88dSmrg "glBeginQuery{Indexed}(target=%s is active)", 43501e04c3fSmrg _mesa_enum_to_string(target)); 4363464ebd5Sriastradh return; 4377117f1b4Smrg } 4387117f1b4Smrg 4397117f1b4Smrg if (id == 0) { 440af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)"); 4417117f1b4Smrg return; 4427117f1b4Smrg } 4437117f1b4Smrg 444cdc920a0Smrg q = _mesa_lookup_query_object(ctx, id); 4457117f1b4Smrg if (!q) { 446af69d88dSmrg if (ctx->API != API_OPENGL_COMPAT) { 447af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 448af69d88dSmrg "glBeginQuery{Indexed}(non-gen name)"); 4497117f1b4Smrg return; 450af69d88dSmrg } else { 451af69d88dSmrg /* create new object */ 452af69d88dSmrg q = ctx->Driver.NewQueryObject(ctx, id); 453af69d88dSmrg if (!q) { 454af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}"); 455af69d88dSmrg return; 456af69d88dSmrg } 4577ec681f3Smrg _mesa_HashInsertLocked(ctx->Query.QueryObjects, id, q, false); 4587117f1b4Smrg } 4597117f1b4Smrg } 4607117f1b4Smrg else { 4617117f1b4Smrg /* pre-existing object */ 4627117f1b4Smrg if (q->Active) { 4637117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 464af69d88dSmrg "glBeginQuery{Indexed}(query already active)"); 4657117f1b4Smrg return; 4667117f1b4Smrg } 46701e04c3fSmrg 46801e04c3fSmrg /* Section 2.14 Asynchronous Queries, page 84 of the OpenGL ES 3.0.4 46901e04c3fSmrg * spec states: 47001e04c3fSmrg * 47101e04c3fSmrg * "BeginQuery generates an INVALID_OPERATION error if any of the 47201e04c3fSmrg * following conditions hold: [...] id is the name of an 47301e04c3fSmrg * existing query object whose type does not match target; [...] 47401e04c3fSmrg * 47501e04c3fSmrg * Similar wording exists in the OpenGL 4.5 spec, section 4.2. QUERY 47601e04c3fSmrg * OBJECTS AND ASYNCHRONOUS QUERIES, page 43. 47701e04c3fSmrg */ 47801e04c3fSmrg if (q->EverBound && q->Target != target) { 47901e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 48001e04c3fSmrg "glBeginQuery{Indexed}(target mismatch)"); 48101e04c3fSmrg return; 48201e04c3fSmrg } 4837117f1b4Smrg } 4847117f1b4Smrg 48501e04c3fSmrg /* This possibly changes the target of a buffer allocated by 48601e04c3fSmrg * CreateQueries. Issue 39) in the ARB_direct_state_access extension states 48701e04c3fSmrg * the following: 48801e04c3fSmrg * 48901e04c3fSmrg * "CreateQueries adds a <target>, so strictly speaking the <target> 49001e04c3fSmrg * command isn't needed for BeginQuery/EndQuery, but in the end, this also 49101e04c3fSmrg * isn't a selector, so we decided not to change it." 49201e04c3fSmrg * 49301e04c3fSmrg * Updating the target of the query object should be acceptable, so let's 49401e04c3fSmrg * do that. 49501e04c3fSmrg */ 49601e04c3fSmrg 497c1f859d4Smrg q->Target = target; 4987117f1b4Smrg q->Active = GL_TRUE; 4997117f1b4Smrg q->Result = 0; 5007117f1b4Smrg q->Ready = GL_FALSE; 501af69d88dSmrg q->EverBound = GL_TRUE; 502af69d88dSmrg q->Stream = index; 5037117f1b4Smrg 5043464ebd5Sriastradh /* XXX should probably refcount query objects */ 5053464ebd5Sriastradh *bindpt = q; 5067117f1b4Smrg 507c1f859d4Smrg ctx->Driver.BeginQuery(ctx, q); 5087117f1b4Smrg} 5097117f1b4Smrg 5107117f1b4Smrg 511af69d88dSmrgvoid GLAPIENTRY 512af69d88dSmrg_mesa_EndQueryIndexed(GLenum target, GLuint index) 5137117f1b4Smrg{ 5143464ebd5Sriastradh struct gl_query_object *q, **bindpt; 5157117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 5167117f1b4Smrg 5173464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 518af69d88dSmrg _mesa_debug(ctx, "glEndQueryIndexed(%s, %u)\n", 51901e04c3fSmrg _mesa_enum_to_string(target), index); 5203464ebd5Sriastradh 521af69d88dSmrg if (!query_error_check_index(ctx, target, index)) 522af69d88dSmrg return; 5237117f1b4Smrg 5247ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 525af69d88dSmrg 526af69d88dSmrg bindpt = get_query_binding_point(ctx, target, index); 5273464ebd5Sriastradh if (!bindpt) { 528af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glEndQuery{Indexed}(target)"); 5293464ebd5Sriastradh return; 5307117f1b4Smrg } 5317117f1b4Smrg 5323464ebd5Sriastradh /* XXX should probably refcount query objects */ 5333464ebd5Sriastradh q = *bindpt; 534af69d88dSmrg 535af69d88dSmrg /* Check for GL_ANY_SAMPLES_PASSED vs GL_SAMPLES_PASSED. */ 536af69d88dSmrg if (q && q->Target != target) { 537af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 538af69d88dSmrg "glEndQuery(target=%s with active query of target %s)", 53901e04c3fSmrg _mesa_enum_to_string(target), 54001e04c3fSmrg _mesa_enum_to_string(q->Target)); 541af69d88dSmrg return; 542af69d88dSmrg } 543af69d88dSmrg 5443464ebd5Sriastradh *bindpt = NULL; 5453464ebd5Sriastradh 5467117f1b4Smrg if (!q || !q->Active) { 5477117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 548af69d88dSmrg "glEndQuery{Indexed}(no matching glBeginQuery{Indexed})"); 5497117f1b4Smrg return; 5507117f1b4Smrg } 5517117f1b4Smrg 5527117f1b4Smrg q->Active = GL_FALSE; 553c1f859d4Smrg ctx->Driver.EndQuery(ctx, q); 5547117f1b4Smrg} 5557117f1b4Smrg 556af69d88dSmrgvoid GLAPIENTRY 557af69d88dSmrg_mesa_BeginQuery(GLenum target, GLuint id) 558af69d88dSmrg{ 559af69d88dSmrg _mesa_BeginQueryIndexed(target, 0, id); 560af69d88dSmrg} 5617117f1b4Smrg 562af69d88dSmrgvoid GLAPIENTRY 563af69d88dSmrg_mesa_EndQuery(GLenum target) 5647117f1b4Smrg{ 565af69d88dSmrg _mesa_EndQueryIndexed(target, 0); 566af69d88dSmrg} 567af69d88dSmrg 568af69d88dSmrgvoid GLAPIENTRY 569af69d88dSmrg_mesa_QueryCounter(GLuint id, GLenum target) 570af69d88dSmrg{ 571af69d88dSmrg struct gl_query_object *q; 5727117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 5737117f1b4Smrg 5743464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 575af69d88dSmrg _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id, 57601e04c3fSmrg _mesa_enum_to_string(target)); 577af69d88dSmrg 578af69d88dSmrg /* error checking */ 579af69d88dSmrg if (target != GL_TIMESTAMP) { 580af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)"); 581af69d88dSmrg return; 582af69d88dSmrg } 583af69d88dSmrg 584af69d88dSmrg if (id == 0) { 585af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)"); 586af69d88dSmrg return; 587af69d88dSmrg } 588af69d88dSmrg 589af69d88dSmrg q = _mesa_lookup_query_object(ctx, id); 590af69d88dSmrg if (!q) { 591af69d88dSmrg /* XXX the Core profile should throw INVALID_OPERATION here */ 592af69d88dSmrg 593af69d88dSmrg /* create new object */ 594af69d88dSmrg q = ctx->Driver.NewQueryObject(ctx, id); 595af69d88dSmrg if (!q) { 596af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter"); 597af69d88dSmrg return; 598af69d88dSmrg } 5997ec681f3Smrg _mesa_HashInsertLocked(ctx->Query.QueryObjects, id, q, false); 600af69d88dSmrg } 601af69d88dSmrg else { 602af69d88dSmrg if (q->Target && q->Target != GL_TIMESTAMP) { 603af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 604af69d88dSmrg "glQueryCounter(id has an invalid target)"); 605af69d88dSmrg return; 606af69d88dSmrg } 607af69d88dSmrg } 608af69d88dSmrg 609af69d88dSmrg if (q->Active) { 610af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)"); 611af69d88dSmrg return; 612af69d88dSmrg } 613af69d88dSmrg 61401e04c3fSmrg /* This possibly changes the target of a buffer allocated by 61501e04c3fSmrg * CreateQueries. Issue 39) in the ARB_direct_state_access extension states 61601e04c3fSmrg * the following: 61701e04c3fSmrg * 61801e04c3fSmrg * "CreateQueries adds a <target>, so strictly speaking the <target> 61901e04c3fSmrg * command isn't needed for BeginQuery/EndQuery, but in the end, this also 62001e04c3fSmrg * isn't a selector, so we decided not to change it." 62101e04c3fSmrg * 62201e04c3fSmrg * Updating the target of the query object should be acceptable, so let's 62301e04c3fSmrg * do that. 62401e04c3fSmrg */ 62501e04c3fSmrg 626af69d88dSmrg q->Target = target; 627af69d88dSmrg q->Result = 0; 628af69d88dSmrg q->Ready = GL_FALSE; 629af69d88dSmrg q->EverBound = GL_TRUE; 630af69d88dSmrg 631af69d88dSmrg if (ctx->Driver.QueryCounter) { 632af69d88dSmrg ctx->Driver.QueryCounter(ctx, q); 633af69d88dSmrg } else { 634af69d88dSmrg /* QueryCounter is implemented using EndQuery without BeginQuery 635af69d88dSmrg * in drivers. This is actually Direct3D and Gallium convention. 636af69d88dSmrg */ 637af69d88dSmrg ctx->Driver.EndQuery(ctx, q); 638af69d88dSmrg } 639af69d88dSmrg} 640af69d88dSmrg 641af69d88dSmrg 642af69d88dSmrgvoid GLAPIENTRY 643af69d88dSmrg_mesa_GetQueryIndexediv(GLenum target, GLuint index, GLenum pname, 644af69d88dSmrg GLint *params) 645af69d88dSmrg{ 646af69d88dSmrg struct gl_query_object *q = NULL, **bindpt = NULL; 647af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 648af69d88dSmrg 649af69d88dSmrg if (MESA_VERBOSE & VERBOSE_API) 650af69d88dSmrg _mesa_debug(ctx, "glGetQueryIndexediv(%s, %u, %s)\n", 65101e04c3fSmrg _mesa_enum_to_string(target), 652af69d88dSmrg index, 65301e04c3fSmrg _mesa_enum_to_string(pname)); 6543464ebd5Sriastradh 655af69d88dSmrg if (!query_error_check_index(ctx, target, index)) 6563464ebd5Sriastradh return; 657af69d88dSmrg 65801e04c3fSmrg /* From the GL_EXT_occlusion_query_boolean spec: 65901e04c3fSmrg * 66001e04c3fSmrg * "The error INVALID_ENUM is generated if GetQueryivEXT is called where 66101e04c3fSmrg * <pname> is not CURRENT_QUERY_EXT." 66201e04c3fSmrg * 66301e04c3fSmrg * Same rule is present also in ES 3.2 spec. 6647ec681f3Smrg * 6657ec681f3Smrg * EXT_disjoint_timer_query extends this with GL_QUERY_COUNTER_BITS. 66601e04c3fSmrg */ 6677ec681f3Smrg if (_mesa_is_gles(ctx)) { 6687ec681f3Smrg switch (pname) { 6697ec681f3Smrg case GL_CURRENT_QUERY: 6707ec681f3Smrg break; 6717ec681f3Smrg case GL_QUERY_COUNTER_BITS: 6727ec681f3Smrg if (_mesa_has_EXT_disjoint_timer_query(ctx)) 6737ec681f3Smrg break; 6747ec681f3Smrg FALLTHROUGH; 6757ec681f3Smrg default: 6767ec681f3Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivEXT(%s)", 6777ec681f3Smrg _mesa_enum_to_string(pname)); 6787ec681f3Smrg } 67901e04c3fSmrg } 68001e04c3fSmrg 681af69d88dSmrg if (target == GL_TIMESTAMP) { 682b9abf16eSmaya if (!_mesa_has_ARB_timer_query(ctx) && 683b9abf16eSmaya !_mesa_has_EXT_disjoint_timer_query(ctx)) { 684af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)"); 685af69d88dSmrg return; 686af69d88dSmrg } 6877117f1b4Smrg } 688af69d88dSmrg else { 689af69d88dSmrg bindpt = get_query_binding_point(ctx, target, index); 690af69d88dSmrg if (!bindpt) { 691af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(target)"); 692af69d88dSmrg return; 693af69d88dSmrg } 6947117f1b4Smrg 695af69d88dSmrg q = *bindpt; 696af69d88dSmrg } 6973464ebd5Sriastradh 6987117f1b4Smrg switch (pname) { 699b9abf16eSmaya case GL_QUERY_COUNTER_BITS: 700af69d88dSmrg switch (target) { 701af69d88dSmrg case GL_SAMPLES_PASSED: 702af69d88dSmrg *params = ctx->Const.QueryCounterBits.SamplesPassed; 703af69d88dSmrg break; 704af69d88dSmrg case GL_ANY_SAMPLES_PASSED: 70501e04c3fSmrg case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: 706af69d88dSmrg /* The minimum value of this is 1 if it's nonzero, and the value 707af69d88dSmrg * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more 708af69d88dSmrg * bits. 709af69d88dSmrg */ 710af69d88dSmrg *params = 1; 711af69d88dSmrg break; 712af69d88dSmrg case GL_TIME_ELAPSED: 713af69d88dSmrg *params = ctx->Const.QueryCounterBits.TimeElapsed; 714af69d88dSmrg break; 715af69d88dSmrg case GL_TIMESTAMP: 716af69d88dSmrg *params = ctx->Const.QueryCounterBits.Timestamp; 717af69d88dSmrg break; 718af69d88dSmrg case GL_PRIMITIVES_GENERATED: 719af69d88dSmrg *params = ctx->Const.QueryCounterBits.PrimitivesGenerated; 720af69d88dSmrg break; 721af69d88dSmrg case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 722af69d88dSmrg *params = ctx->Const.QueryCounterBits.PrimitivesWritten; 723af69d88dSmrg break; 724b9abf16eSmaya case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW: 725b9abf16eSmaya case GL_TRANSFORM_FEEDBACK_OVERFLOW: 72601e04c3fSmrg /* The minimum value of this is 1 if it's nonzero, and the value 72701e04c3fSmrg * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more 72801e04c3fSmrg * bits. 72901e04c3fSmrg */ 73001e04c3fSmrg *params = 1; 73101e04c3fSmrg break; 732b9abf16eSmaya case GL_VERTICES_SUBMITTED: 73301e04c3fSmrg *params = ctx->Const.QueryCounterBits.VerticesSubmitted; 73401e04c3fSmrg break; 735b9abf16eSmaya case GL_PRIMITIVES_SUBMITTED: 73601e04c3fSmrg *params = ctx->Const.QueryCounterBits.PrimitivesSubmitted; 73701e04c3fSmrg break; 738b9abf16eSmaya case GL_VERTEX_SHADER_INVOCATIONS: 73901e04c3fSmrg *params = ctx->Const.QueryCounterBits.VsInvocations; 74001e04c3fSmrg break; 741b9abf16eSmaya case GL_TESS_CONTROL_SHADER_PATCHES: 74201e04c3fSmrg *params = ctx->Const.QueryCounterBits.TessPatches; 74301e04c3fSmrg break; 744b9abf16eSmaya case GL_TESS_EVALUATION_SHADER_INVOCATIONS: 74501e04c3fSmrg *params = ctx->Const.QueryCounterBits.TessInvocations; 74601e04c3fSmrg break; 74701e04c3fSmrg case GL_GEOMETRY_SHADER_INVOCATIONS: 74801e04c3fSmrg *params = ctx->Const.QueryCounterBits.GsInvocations; 74901e04c3fSmrg break; 750b9abf16eSmaya case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED: 75101e04c3fSmrg *params = ctx->Const.QueryCounterBits.GsPrimitives; 75201e04c3fSmrg break; 753b9abf16eSmaya case GL_FRAGMENT_SHADER_INVOCATIONS: 75401e04c3fSmrg *params = ctx->Const.QueryCounterBits.FsInvocations; 75501e04c3fSmrg break; 756b9abf16eSmaya case GL_COMPUTE_SHADER_INVOCATIONS: 75701e04c3fSmrg *params = ctx->Const.QueryCounterBits.ComputeInvocations; 75801e04c3fSmrg break; 759b9abf16eSmaya case GL_CLIPPING_INPUT_PRIMITIVES: 76001e04c3fSmrg *params = ctx->Const.QueryCounterBits.ClInPrimitives; 76101e04c3fSmrg break; 762b9abf16eSmaya case GL_CLIPPING_OUTPUT_PRIMITIVES: 76301e04c3fSmrg *params = ctx->Const.QueryCounterBits.ClOutPrimitives; 76401e04c3fSmrg break; 765af69d88dSmrg default: 766af69d88dSmrg _mesa_problem(ctx, 767af69d88dSmrg "Unknown target in glGetQueryIndexediv(target = %s)", 76801e04c3fSmrg _mesa_enum_to_string(target)); 769af69d88dSmrg *params = 0; 770af69d88dSmrg break; 771af69d88dSmrg } 7727117f1b4Smrg break; 773b9abf16eSmaya case GL_CURRENT_QUERY: 774af69d88dSmrg *params = (q && q->Target == target) ? q->Id : 0; 7757117f1b4Smrg break; 7767117f1b4Smrg default: 777af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(pname)"); 7787117f1b4Smrg return; 7797117f1b4Smrg } 7807117f1b4Smrg} 7817117f1b4Smrg 782af69d88dSmrgvoid GLAPIENTRY 783af69d88dSmrg_mesa_GetQueryiv(GLenum target, GLenum pname, GLint *params) 784af69d88dSmrg{ 785af69d88dSmrg _mesa_GetQueryIndexediv(target, 0, pname, params); 786af69d88dSmrg} 7877117f1b4Smrg 78801e04c3fSmrgstatic void 78901e04c3fSmrgget_query_object(struct gl_context *ctx, const char *func, 79001e04c3fSmrg GLuint id, GLenum pname, GLenum ptype, 79101e04c3fSmrg struct gl_buffer_object *buf, intptr_t offset) 7927117f1b4Smrg{ 7937117f1b4Smrg struct gl_query_object *q = NULL; 79401e04c3fSmrg uint64_t value; 7957117f1b4Smrg 7963464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 79701e04c3fSmrg _mesa_debug(ctx, "%s(%u, %s)\n", func, id, 79801e04c3fSmrg _mesa_enum_to_string(pname)); 7993464ebd5Sriastradh 8007117f1b4Smrg if (id) 801cdc920a0Smrg q = _mesa_lookup_query_object(ctx, id); 8027117f1b4Smrg 80301e04c3fSmrg if (!q || q->Active || !q->EverBound) { 8047117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 80501e04c3fSmrg "%s(id=%d is invalid or active)", func, id); 80601e04c3fSmrg return; 80701e04c3fSmrg } 80801e04c3fSmrg 80901e04c3fSmrg /* From GL_EXT_occlusion_query_boolean spec: 81001e04c3fSmrg * 81101e04c3fSmrg * "Accepted by the <pname> parameter of GetQueryObjectivEXT and 81201e04c3fSmrg * GetQueryObjectuivEXT: 81301e04c3fSmrg * 81401e04c3fSmrg * QUERY_RESULT_EXT 0x8866 81501e04c3fSmrg * QUERY_RESULT_AVAILABLE_EXT 0x8867" 81601e04c3fSmrg * 81701e04c3fSmrg * Same rule is present also in ES 3.2 spec. 81801e04c3fSmrg */ 81901e04c3fSmrg if (_mesa_is_gles(ctx) && 82001e04c3fSmrg (pname != GL_QUERY_RESULT && pname != GL_QUERY_RESULT_AVAILABLE)) { 82101e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(%s)", func, 82201e04c3fSmrg _mesa_enum_to_string(pname)); 8237117f1b4Smrg return; 8247117f1b4Smrg } 8257117f1b4Smrg 8267ec681f3Smrg if (buf) { 82701e04c3fSmrg bool is_64bit = ptype == GL_INT64_ARB || 82801e04c3fSmrg ptype == GL_UNSIGNED_INT64_ARB; 829b9abf16eSmaya if (!_mesa_has_ARB_query_buffer_object(ctx)) { 83001e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(not supported)", func); 83101e04c3fSmrg return; 83201e04c3fSmrg } 83301e04c3fSmrg if (buf->Size < offset + 4 * (is_64bit ? 2 : 1)) { 83401e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(out of bounds)", func); 83501e04c3fSmrg return; 83601e04c3fSmrg } 83701e04c3fSmrg 83801e04c3fSmrg if (offset < 0) { 83901e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset is negative)", func); 84001e04c3fSmrg return; 84101e04c3fSmrg } 84201e04c3fSmrg 84301e04c3fSmrg switch (pname) { 84401e04c3fSmrg case GL_QUERY_RESULT: 84501e04c3fSmrg case GL_QUERY_RESULT_NO_WAIT: 84601e04c3fSmrg case GL_QUERY_RESULT_AVAILABLE: 84701e04c3fSmrg case GL_QUERY_TARGET: 84801e04c3fSmrg ctx->Driver.StoreQueryResult(ctx, q, buf, offset, pname, ptype); 84901e04c3fSmrg return; 85001e04c3fSmrg } 85101e04c3fSmrg 85201e04c3fSmrg /* fall through to get error below */ 85301e04c3fSmrg } 85401e04c3fSmrg 8557117f1b4Smrg switch (pname) { 85601e04c3fSmrg case GL_QUERY_RESULT: 85701e04c3fSmrg if (!q->Ready) 85801e04c3fSmrg ctx->Driver.WaitQuery(ctx, q); 85901e04c3fSmrg value = q->Result; 86001e04c3fSmrg break; 86101e04c3fSmrg case GL_QUERY_RESULT_NO_WAIT: 862b9abf16eSmaya if (!_mesa_has_ARB_query_buffer_object(ctx)) 86301e04c3fSmrg goto invalid_enum; 86401e04c3fSmrg ctx->Driver.CheckQuery(ctx, q); 86501e04c3fSmrg if (!q->Ready) 8667117f1b4Smrg return; 86701e04c3fSmrg value = q->Result; 86801e04c3fSmrg break; 86901e04c3fSmrg case GL_QUERY_RESULT_AVAILABLE: 87001e04c3fSmrg if (!q->Ready) 87101e04c3fSmrg ctx->Driver.CheckQuery(ctx, q); 87201e04c3fSmrg value = q->Ready; 87301e04c3fSmrg break; 87401e04c3fSmrg case GL_QUERY_TARGET: 87501e04c3fSmrg value = q->Target; 87601e04c3fSmrg break; 87701e04c3fSmrg default: 87801e04c3fSmrginvalid_enum: 87901e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=%s)", 88001e04c3fSmrg func, _mesa_enum_to_string(pname)); 88101e04c3fSmrg return; 88201e04c3fSmrg } 88301e04c3fSmrg 88401e04c3fSmrg switch (ptype) { 88501e04c3fSmrg case GL_INT: { 88601e04c3fSmrg GLint *param = (GLint *)offset; 88701e04c3fSmrg if (value > 0x7fffffff) 88801e04c3fSmrg *param = 0x7fffffff; 88901e04c3fSmrg else 89001e04c3fSmrg *param = value; 89101e04c3fSmrg break; 89201e04c3fSmrg } 89301e04c3fSmrg case GL_UNSIGNED_INT: { 89401e04c3fSmrg GLuint *param = (GLuint *)offset; 89501e04c3fSmrg if (value > 0xffffffff) 89601e04c3fSmrg *param = 0xffffffff; 89701e04c3fSmrg else 89801e04c3fSmrg *param = value; 89901e04c3fSmrg break; 90001e04c3fSmrg } 90101e04c3fSmrg case GL_INT64_ARB: 90201e04c3fSmrg case GL_UNSIGNED_INT64_ARB: { 90301e04c3fSmrg GLuint64EXT *param = (GLuint64EXT *)offset; 90401e04c3fSmrg *param = value; 90501e04c3fSmrg break; 9067117f1b4Smrg } 90701e04c3fSmrg default: 90801e04c3fSmrg unreachable("unexpected ptype"); 90901e04c3fSmrg } 91001e04c3fSmrg} 91101e04c3fSmrg 91201e04c3fSmrgvoid GLAPIENTRY 91301e04c3fSmrg_mesa_GetQueryObjectiv(GLuint id, GLenum pname, GLint *params) 91401e04c3fSmrg{ 91501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 91601e04c3fSmrg 91701e04c3fSmrg get_query_object(ctx, "glGetQueryObjectiv", 91801e04c3fSmrg id, pname, GL_INT, ctx->QueryBuffer, (intptr_t)params); 9197117f1b4Smrg} 9207117f1b4Smrg 9217117f1b4Smrg 922af69d88dSmrgvoid GLAPIENTRY 923af69d88dSmrg_mesa_GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params) 9247117f1b4Smrg{ 9257117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 9267117f1b4Smrg 92701e04c3fSmrg get_query_object(ctx, "glGetQueryObjectuiv", 92801e04c3fSmrg id, pname, GL_UNSIGNED_INT, 92901e04c3fSmrg ctx->QueryBuffer, (intptr_t)params); 93001e04c3fSmrg} 9313464ebd5Sriastradh 9327117f1b4Smrg 93301e04c3fSmrg/** 93401e04c3fSmrg * New with GL_EXT_timer_query 93501e04c3fSmrg */ 93601e04c3fSmrgvoid GLAPIENTRY 93701e04c3fSmrg_mesa_GetQueryObjecti64v(GLuint id, GLenum pname, GLint64EXT *params) 93801e04c3fSmrg{ 93901e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 9407117f1b4Smrg 94101e04c3fSmrg get_query_object(ctx, "glGetQueryObjecti64v", 94201e04c3fSmrg id, pname, GL_INT64_ARB, 94301e04c3fSmrg ctx->QueryBuffer, (intptr_t)params); 9447117f1b4Smrg} 9457117f1b4Smrg 9467117f1b4Smrg 9477117f1b4Smrg/** 9487117f1b4Smrg * New with GL_EXT_timer_query 9497117f1b4Smrg */ 950af69d88dSmrgvoid GLAPIENTRY 95101e04c3fSmrg_mesa_GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64EXT *params) 9527117f1b4Smrg{ 9537117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 9547117f1b4Smrg 95501e04c3fSmrg get_query_object(ctx, "glGetQueryObjectui64v", 95601e04c3fSmrg id, pname, GL_UNSIGNED_INT64_ARB, 95701e04c3fSmrg ctx->QueryBuffer, (intptr_t)params); 95801e04c3fSmrg} 9593464ebd5Sriastradh 96001e04c3fSmrg/** 96101e04c3fSmrg * New with GL_ARB_query_buffer_object 96201e04c3fSmrg */ 96301e04c3fSmrgvoid GLAPIENTRY 96401e04c3fSmrg_mesa_GetQueryBufferObjectiv(GLuint id, GLuint buffer, GLenum pname, 96501e04c3fSmrg GLintptr offset) 96601e04c3fSmrg{ 96701e04c3fSmrg struct gl_buffer_object *buf; 96801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 9697117f1b4Smrg 97001e04c3fSmrg buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectiv"); 97101e04c3fSmrg if (!buf) 9727117f1b4Smrg return; 9737117f1b4Smrg 97401e04c3fSmrg get_query_object(ctx, "glGetQueryBufferObjectiv", 97501e04c3fSmrg id, pname, GL_INT, buf, offset); 9767117f1b4Smrg} 9777117f1b4Smrg 9787117f1b4Smrg 979af69d88dSmrgvoid GLAPIENTRY 98001e04c3fSmrg_mesa_GetQueryBufferObjectuiv(GLuint id, GLuint buffer, GLenum pname, 98101e04c3fSmrg GLintptr offset) 9827117f1b4Smrg{ 98301e04c3fSmrg struct gl_buffer_object *buf; 9847117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 9857117f1b4Smrg 98601e04c3fSmrg buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectuiv"); 98701e04c3fSmrg if (!buf) 98801e04c3fSmrg return; 9893464ebd5Sriastradh 99001e04c3fSmrg get_query_object(ctx, "glGetQueryBufferObjectuiv", 99101e04c3fSmrg id, pname, GL_UNSIGNED_INT, buf, offset); 99201e04c3fSmrg} 9937117f1b4Smrg 99401e04c3fSmrg 99501e04c3fSmrgvoid GLAPIENTRY 99601e04c3fSmrg_mesa_GetQueryBufferObjecti64v(GLuint id, GLuint buffer, GLenum pname, 99701e04c3fSmrg GLintptr offset) 99801e04c3fSmrg{ 99901e04c3fSmrg struct gl_buffer_object *buf; 100001e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 100101e04c3fSmrg 100201e04c3fSmrg buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjecti64v"); 100301e04c3fSmrg if (!buf) 10047117f1b4Smrg return; 10057117f1b4Smrg 100601e04c3fSmrg get_query_object(ctx, "glGetQueryBufferObjecti64v", 100701e04c3fSmrg id, pname, GL_INT64_ARB, buf, offset); 10087117f1b4Smrg} 10097117f1b4Smrg 101001e04c3fSmrg 101101e04c3fSmrgvoid GLAPIENTRY 101201e04c3fSmrg_mesa_GetQueryBufferObjectui64v(GLuint id, GLuint buffer, GLenum pname, 101301e04c3fSmrg GLintptr offset) 101401e04c3fSmrg{ 101501e04c3fSmrg struct gl_buffer_object *buf; 101601e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 101701e04c3fSmrg 101801e04c3fSmrg buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectui64v"); 101901e04c3fSmrg if (!buf) 102001e04c3fSmrg return; 102101e04c3fSmrg 102201e04c3fSmrg get_query_object(ctx, "glGetQueryBufferObjectui64v", 102301e04c3fSmrg id, pname, GL_UNSIGNED_INT64_ARB, buf, offset); 102401e04c3fSmrg} 102501e04c3fSmrg 102601e04c3fSmrg 10277117f1b4Smrg/** 10287117f1b4Smrg * Allocate/init the context state related to query objects. 10297117f1b4Smrg */ 10307117f1b4Smrgvoid 10313464ebd5Sriastradh_mesa_init_queryobj(struct gl_context *ctx) 10327117f1b4Smrg{ 10337117f1b4Smrg ctx->Query.QueryObjects = _mesa_NewHashTable(); 10347117f1b4Smrg ctx->Query.CurrentOcclusionObject = NULL; 1035af69d88dSmrg 1036af69d88dSmrg ctx->Const.QueryCounterBits.SamplesPassed = 64; 1037af69d88dSmrg ctx->Const.QueryCounterBits.TimeElapsed = 64; 1038af69d88dSmrg ctx->Const.QueryCounterBits.Timestamp = 64; 1039af69d88dSmrg ctx->Const.QueryCounterBits.PrimitivesGenerated = 64; 1040af69d88dSmrg ctx->Const.QueryCounterBits.PrimitivesWritten = 64; 104101e04c3fSmrg 104201e04c3fSmrg ctx->Const.QueryCounterBits.VerticesSubmitted = 64; 104301e04c3fSmrg ctx->Const.QueryCounterBits.PrimitivesSubmitted = 64; 104401e04c3fSmrg ctx->Const.QueryCounterBits.VsInvocations = 64; 104501e04c3fSmrg ctx->Const.QueryCounterBits.TessPatches = 64; 104601e04c3fSmrg ctx->Const.QueryCounterBits.TessInvocations = 64; 104701e04c3fSmrg ctx->Const.QueryCounterBits.GsInvocations = 64; 104801e04c3fSmrg ctx->Const.QueryCounterBits.GsPrimitives = 64; 104901e04c3fSmrg ctx->Const.QueryCounterBits.FsInvocations = 64; 105001e04c3fSmrg ctx->Const.QueryCounterBits.ComputeInvocations = 64; 105101e04c3fSmrg ctx->Const.QueryCounterBits.ClInPrimitives = 64; 105201e04c3fSmrg ctx->Const.QueryCounterBits.ClOutPrimitives = 64; 10537117f1b4Smrg} 10547117f1b4Smrg 10557117f1b4Smrg 10567117f1b4Smrg/** 10577117f1b4Smrg * Callback for deleting a query object. Called by _mesa_HashDeleteAll(). 10587117f1b4Smrg */ 10597117f1b4Smrgstatic void 10607ec681f3Smrgdelete_queryobj_cb(void *data, void *userData) 10617117f1b4Smrg{ 10627117f1b4Smrg struct gl_query_object *q= (struct gl_query_object *) data; 10633464ebd5Sriastradh struct gl_context *ctx = (struct gl_context *)userData; 1064c1f859d4Smrg ctx->Driver.DeleteQuery(ctx, q); 10657117f1b4Smrg} 10667117f1b4Smrg 10677117f1b4Smrg 10687117f1b4Smrg/** 10697117f1b4Smrg * Free the context state related to query objects. 10707117f1b4Smrg */ 10717117f1b4Smrgvoid 10723464ebd5Sriastradh_mesa_free_queryobj_data(struct gl_context *ctx) 10737117f1b4Smrg{ 1074c1f859d4Smrg _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx); 10757117f1b4Smrg _mesa_DeleteHashTable(ctx->Query.QueryObjects); 10767117f1b4Smrg} 1077