queryobj.c revision 01e04c3f
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{ 14901e04c3fSmrg const int which = target - GL_VERTICES_SUBMITTED_ARB; 15001e04c3fSmrg assert(which < MAX_PIPELINE_STATISTICS); 15101e04c3fSmrg 15201e04c3fSmrg if (!_mesa_is_desktop_gl(ctx) || 15301e04c3fSmrg !ctx->Extensions.ARB_pipeline_statistics_query) 15401e04c3fSmrg return NULL; 15501e04c3fSmrg 15601e04c3fSmrg return &ctx->Query.pipeline_stats[which]; 15701e04c3fSmrg} 1584a49301eSmrg 1593464ebd5Sriastradh/** 160af69d88dSmrg * Return pointer to the query object binding point for the given target and 161af69d88dSmrg * index. 1623464ebd5Sriastradh * \return NULL if invalid target, else the address of binding point 1633464ebd5Sriastradh */ 1643464ebd5Sriastradhstatic struct gl_query_object ** 165af69d88dSmrgget_query_binding_point(struct gl_context *ctx, GLenum target, GLuint index) 1663464ebd5Sriastradh{ 16701e04c3fSmrg 16801e04c3fSmrg /* From GL_EXT_occlusion_query_boolean spec: 16901e04c3fSmrg * 17001e04c3fSmrg * "Accepted by the <target> parameter of BeginQueryEXT, EndQueryEXT, 17101e04c3fSmrg * and GetQueryivEXT: 17201e04c3fSmrg * 17301e04c3fSmrg * ANY_SAMPLES_PASSED_EXT 0x8C2F 17401e04c3fSmrg * ANY_SAMPLES_PASSED_CONSERVATIVE_EXT 0x8D6A" 17501e04c3fSmrg */ 17601e04c3fSmrg if ((_mesa_is_gles(ctx) && ctx->Version == 20) && 17701e04c3fSmrg (target != GL_ANY_SAMPLES_PASSED && 17801e04c3fSmrg target != GL_ANY_SAMPLES_PASSED_CONSERVATIVE)) 17901e04c3fSmrg return NULL; 18001e04c3fSmrg 1813464ebd5Sriastradh switch (target) { 1823464ebd5Sriastradh case GL_SAMPLES_PASSED_ARB: 1833464ebd5Sriastradh if (ctx->Extensions.ARB_occlusion_query) 1843464ebd5Sriastradh return &ctx->Query.CurrentOcclusionObject; 1853464ebd5Sriastradh else 1863464ebd5Sriastradh return NULL; 1873464ebd5Sriastradh case GL_ANY_SAMPLES_PASSED: 1883464ebd5Sriastradh if (ctx->Extensions.ARB_occlusion_query2) 1893464ebd5Sriastradh return &ctx->Query.CurrentOcclusionObject; 1903464ebd5Sriastradh else 1913464ebd5Sriastradh return NULL; 192af69d88dSmrg case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: 193af69d88dSmrg if (ctx->Extensions.ARB_ES3_compatibility 194af69d88dSmrg || (ctx->API == API_OPENGLES2 && ctx->Version >= 30)) 195af69d88dSmrg return &ctx->Query.CurrentOcclusionObject; 196af69d88dSmrg else 197af69d88dSmrg return NULL; 1983464ebd5Sriastradh case GL_TIME_ELAPSED_EXT: 1993464ebd5Sriastradh if (ctx->Extensions.EXT_timer_query) 2003464ebd5Sriastradh return &ctx->Query.CurrentTimerObject; 2013464ebd5Sriastradh else 2023464ebd5Sriastradh return NULL; 2033464ebd5Sriastradh case GL_PRIMITIVES_GENERATED: 2043464ebd5Sriastradh if (ctx->Extensions.EXT_transform_feedback) 205af69d88dSmrg return &ctx->Query.PrimitivesGenerated[index]; 2063464ebd5Sriastradh else 2073464ebd5Sriastradh return NULL; 2083464ebd5Sriastradh case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 2093464ebd5Sriastradh if (ctx->Extensions.EXT_transform_feedback) 210af69d88dSmrg return &ctx->Query.PrimitivesWritten[index]; 2113464ebd5Sriastradh else 2123464ebd5Sriastradh return NULL; 21301e04c3fSmrg case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB: 21401e04c3fSmrg if (ctx->Extensions.ARB_transform_feedback_overflow_query) 21501e04c3fSmrg return &ctx->Query.TransformFeedbackOverflow[index]; 21601e04c3fSmrg else 21701e04c3fSmrg return NULL; 21801e04c3fSmrg case GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB: 21901e04c3fSmrg if (ctx->Extensions.ARB_transform_feedback_overflow_query) 22001e04c3fSmrg return &ctx->Query.TransformFeedbackOverflowAny; 22101e04c3fSmrg else 22201e04c3fSmrg return NULL; 22301e04c3fSmrg 22401e04c3fSmrg case GL_VERTICES_SUBMITTED_ARB: 22501e04c3fSmrg case GL_PRIMITIVES_SUBMITTED_ARB: 22601e04c3fSmrg case GL_VERTEX_SHADER_INVOCATIONS_ARB: 22701e04c3fSmrg case GL_FRAGMENT_SHADER_INVOCATIONS_ARB: 22801e04c3fSmrg case GL_CLIPPING_INPUT_PRIMITIVES_ARB: 22901e04c3fSmrg case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB: 23001e04c3fSmrg return get_pipe_stats_binding_point(ctx, target); 23101e04c3fSmrg 23201e04c3fSmrg case GL_GEOMETRY_SHADER_INVOCATIONS: 23301e04c3fSmrg /* GL_GEOMETRY_SHADER_INVOCATIONS is defined in a non-sequential order */ 23401e04c3fSmrg target = GL_VERTICES_SUBMITTED_ARB + MAX_PIPELINE_STATISTICS - 1; 23501e04c3fSmrg /* fallthrough */ 23601e04c3fSmrg case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB: 23701e04c3fSmrg if (_mesa_has_geometry_shaders(ctx)) 23801e04c3fSmrg return get_pipe_stats_binding_point(ctx, target); 23901e04c3fSmrg else 24001e04c3fSmrg return NULL; 24101e04c3fSmrg 24201e04c3fSmrg case GL_TESS_CONTROL_SHADER_PATCHES_ARB: 24301e04c3fSmrg case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB: 24401e04c3fSmrg if (_mesa_has_tessellation(ctx)) 24501e04c3fSmrg return get_pipe_stats_binding_point(ctx, target); 24601e04c3fSmrg else 24701e04c3fSmrg return NULL; 24801e04c3fSmrg 24901e04c3fSmrg case GL_COMPUTE_SHADER_INVOCATIONS_ARB: 25001e04c3fSmrg if (_mesa_has_compute_shaders(ctx)) 25101e04c3fSmrg return get_pipe_stats_binding_point(ctx, target); 25201e04c3fSmrg else 25301e04c3fSmrg return NULL; 25401e04c3fSmrg 2553464ebd5Sriastradh default: 2563464ebd5Sriastradh return NULL; 2573464ebd5Sriastradh } 2583464ebd5Sriastradh} 2593464ebd5Sriastradh 26001e04c3fSmrg/** 26101e04c3fSmrg * Create $n query objects and store them in *ids. Make them of type $target 26201e04c3fSmrg * if dsa is set. Called from _mesa_GenQueries() and _mesa_CreateQueries(). 26301e04c3fSmrg */ 26401e04c3fSmrgstatic void 26501e04c3fSmrgcreate_queries(struct gl_context *ctx, GLenum target, GLsizei n, GLuint *ids, 26601e04c3fSmrg bool dsa) 2677117f1b4Smrg{ 26801e04c3fSmrg const char *func = dsa ? "glGenQueries" : "glCreateQueries"; 2697117f1b4Smrg GLuint first; 2707117f1b4Smrg 2713464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 27201e04c3fSmrg _mesa_debug(ctx, "%s(%d)\n", func, n); 2733464ebd5Sriastradh 2747117f1b4Smrg if (n < 0) { 27501e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func); 2767117f1b4Smrg return; 2777117f1b4Smrg } 2787117f1b4Smrg 2797117f1b4Smrg first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n); 2807117f1b4Smrg if (first) { 2817117f1b4Smrg GLsizei i; 2827117f1b4Smrg for (i = 0; i < n; i++) { 2837117f1b4Smrg struct gl_query_object *q 2847117f1b4Smrg = ctx->Driver.NewQueryObject(ctx, first + i); 2857117f1b4Smrg if (!q) { 28601e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); 2877117f1b4Smrg return; 28801e04c3fSmrg } else if (dsa) { 28901e04c3fSmrg /* Do the equivalent of binding the buffer with a target */ 29001e04c3fSmrg q->Target = target; 29101e04c3fSmrg q->EverBound = GL_TRUE; 2927117f1b4Smrg } 2937117f1b4Smrg ids[i] = first + i; 29401e04c3fSmrg _mesa_HashInsertLocked(ctx->Query.QueryObjects, first + i, q); 2957117f1b4Smrg } 2967117f1b4Smrg } 2977117f1b4Smrg} 2987117f1b4Smrg 29901e04c3fSmrgvoid GLAPIENTRY 30001e04c3fSmrg_mesa_GenQueries(GLsizei n, GLuint *ids) 30101e04c3fSmrg{ 30201e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 30301e04c3fSmrg create_queries(ctx, 0, n, ids, false); 30401e04c3fSmrg} 30501e04c3fSmrg 30601e04c3fSmrgvoid GLAPIENTRY 30701e04c3fSmrg_mesa_CreateQueries(GLenum target, GLsizei n, GLuint *ids) 30801e04c3fSmrg{ 30901e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 31001e04c3fSmrg 31101e04c3fSmrg switch (target) { 31201e04c3fSmrg case GL_SAMPLES_PASSED: 31301e04c3fSmrg case GL_ANY_SAMPLES_PASSED: 31401e04c3fSmrg case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: 31501e04c3fSmrg case GL_TIME_ELAPSED: 31601e04c3fSmrg case GL_TIMESTAMP: 31701e04c3fSmrg case GL_PRIMITIVES_GENERATED: 31801e04c3fSmrg case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 31901e04c3fSmrg case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB: 32001e04c3fSmrg case GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB: 32101e04c3fSmrg break; 32201e04c3fSmrg default: 32301e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glCreateQueries(invalid target = %s)", 32401e04c3fSmrg _mesa_enum_to_string(target)); 32501e04c3fSmrg return; 32601e04c3fSmrg } 32701e04c3fSmrg 32801e04c3fSmrg create_queries(ctx, target, n, ids, true); 32901e04c3fSmrg} 33001e04c3fSmrg 3317117f1b4Smrg 332af69d88dSmrgvoid GLAPIENTRY 333af69d88dSmrg_mesa_DeleteQueries(GLsizei n, const GLuint *ids) 3347117f1b4Smrg{ 3357117f1b4Smrg GLint i; 3367117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 3373464ebd5Sriastradh FLUSH_VERTICES(ctx, 0); 3383464ebd5Sriastradh 3393464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 340af69d88dSmrg _mesa_debug(ctx, "glDeleteQueries(%d)\n", n); 3417117f1b4Smrg 3427117f1b4Smrg if (n < 0) { 3437117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)"); 3447117f1b4Smrg return; 3457117f1b4Smrg } 3467117f1b4Smrg 3477117f1b4Smrg for (i = 0; i < n; i++) { 3487117f1b4Smrg if (ids[i] > 0) { 349cdc920a0Smrg struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]); 3507117f1b4Smrg if (q) { 351af69d88dSmrg if (q->Active) { 352af69d88dSmrg struct gl_query_object **bindpt; 353af69d88dSmrg bindpt = get_query_binding_point(ctx, q->Target, q->Stream); 354af69d88dSmrg assert(bindpt); /* Should be non-null for active q. */ 355af69d88dSmrg if (bindpt) { 356af69d88dSmrg *bindpt = NULL; 357af69d88dSmrg } 358af69d88dSmrg q->Active = GL_FALSE; 359af69d88dSmrg ctx->Driver.EndQuery(ctx, q); 360af69d88dSmrg } 36101e04c3fSmrg _mesa_HashRemoveLocked(ctx->Query.QueryObjects, ids[i]); 362c1f859d4Smrg ctx->Driver.DeleteQuery(ctx, q); 3637117f1b4Smrg } 3647117f1b4Smrg } 3657117f1b4Smrg } 3667117f1b4Smrg} 3677117f1b4Smrg 3687117f1b4Smrg 369af69d88dSmrgGLboolean GLAPIENTRY 370af69d88dSmrg_mesa_IsQuery(GLuint id) 3717117f1b4Smrg{ 372af69d88dSmrg struct gl_query_object *q; 373af69d88dSmrg 3747117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 3757117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 3767117f1b4Smrg 3773464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 3783464ebd5Sriastradh _mesa_debug(ctx, "glIsQuery(%u)\n", id); 3793464ebd5Sriastradh 380af69d88dSmrg if (id == 0) 381af69d88dSmrg return GL_FALSE; 382af69d88dSmrg 383af69d88dSmrg q = _mesa_lookup_query_object(ctx, id); 384af69d88dSmrg if (q == NULL) 3857117f1b4Smrg return GL_FALSE; 386af69d88dSmrg 387af69d88dSmrg return q->EverBound; 3887117f1b4Smrg} 3897117f1b4Smrg 390af69d88dSmrgstatic GLboolean 391af69d88dSmrgquery_error_check_index(struct gl_context *ctx, GLenum target, GLuint index) 392af69d88dSmrg{ 393af69d88dSmrg switch (target) { 394af69d88dSmrg case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 395af69d88dSmrg case GL_PRIMITIVES_GENERATED: 39601e04c3fSmrg case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB: 397af69d88dSmrg if (index >= ctx->Const.MaxVertexStreams) { 398af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 399af69d88dSmrg "glBeginQueryIndexed(index>=MaxVertexStreams)"); 400af69d88dSmrg return GL_FALSE; 401af69d88dSmrg } 402af69d88dSmrg break; 403af69d88dSmrg default: 404af69d88dSmrg if (index > 0) { 405af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glBeginQueryIndexed(index>0)"); 406af69d88dSmrg return GL_FALSE; 407af69d88dSmrg } 408af69d88dSmrg } 409af69d88dSmrg return GL_TRUE; 410af69d88dSmrg} 4117117f1b4Smrg 412af69d88dSmrgvoid GLAPIENTRY 413af69d88dSmrg_mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id) 4147117f1b4Smrg{ 4153464ebd5Sriastradh struct gl_query_object *q, **bindpt; 4167117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 4177117f1b4Smrg 4183464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 419af69d88dSmrg _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n", 42001e04c3fSmrg _mesa_enum_to_string(target), index, id); 4213464ebd5Sriastradh 422af69d88dSmrg if (!query_error_check_index(ctx, target, index)) 423af69d88dSmrg return; 424af69d88dSmrg 425af69d88dSmrg FLUSH_VERTICES(ctx, 0); 4267117f1b4Smrg 427af69d88dSmrg bindpt = get_query_binding_point(ctx, target, index); 4283464ebd5Sriastradh if (!bindpt) { 429af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)"); 430af69d88dSmrg return; 431af69d88dSmrg } 432af69d88dSmrg 433af69d88dSmrg /* From the GL_ARB_occlusion_query spec: 434af69d88dSmrg * 435af69d88dSmrg * "If BeginQueryARB is called while another query is already in 436af69d88dSmrg * progress with the same target, an INVALID_OPERATION error is 437af69d88dSmrg * generated." 438af69d88dSmrg */ 439af69d88dSmrg if (*bindpt) { 440af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 441af69d88dSmrg "glBeginQuery{Indexed}(target=%s is active)", 44201e04c3fSmrg _mesa_enum_to_string(target)); 4433464ebd5Sriastradh return; 4447117f1b4Smrg } 4457117f1b4Smrg 4467117f1b4Smrg if (id == 0) { 447af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)"); 4487117f1b4Smrg return; 4497117f1b4Smrg } 4507117f1b4Smrg 451cdc920a0Smrg q = _mesa_lookup_query_object(ctx, id); 4527117f1b4Smrg if (!q) { 453af69d88dSmrg if (ctx->API != API_OPENGL_COMPAT) { 454af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 455af69d88dSmrg "glBeginQuery{Indexed}(non-gen name)"); 4567117f1b4Smrg return; 457af69d88dSmrg } else { 458af69d88dSmrg /* create new object */ 459af69d88dSmrg q = ctx->Driver.NewQueryObject(ctx, id); 460af69d88dSmrg if (!q) { 461af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}"); 462af69d88dSmrg return; 463af69d88dSmrg } 46401e04c3fSmrg _mesa_HashInsertLocked(ctx->Query.QueryObjects, id, q); 4657117f1b4Smrg } 4667117f1b4Smrg } 4677117f1b4Smrg else { 4687117f1b4Smrg /* pre-existing object */ 4697117f1b4Smrg if (q->Active) { 4707117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 471af69d88dSmrg "glBeginQuery{Indexed}(query already active)"); 4727117f1b4Smrg return; 4737117f1b4Smrg } 47401e04c3fSmrg 47501e04c3fSmrg /* Section 2.14 Asynchronous Queries, page 84 of the OpenGL ES 3.0.4 47601e04c3fSmrg * spec states: 47701e04c3fSmrg * 47801e04c3fSmrg * "BeginQuery generates an INVALID_OPERATION error if any of the 47901e04c3fSmrg * following conditions hold: [...] id is the name of an 48001e04c3fSmrg * existing query object whose type does not match target; [...] 48101e04c3fSmrg * 48201e04c3fSmrg * Similar wording exists in the OpenGL 4.5 spec, section 4.2. QUERY 48301e04c3fSmrg * OBJECTS AND ASYNCHRONOUS QUERIES, page 43. 48401e04c3fSmrg */ 48501e04c3fSmrg if (q->EverBound && q->Target != target) { 48601e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 48701e04c3fSmrg "glBeginQuery{Indexed}(target mismatch)"); 48801e04c3fSmrg return; 48901e04c3fSmrg } 4907117f1b4Smrg } 4917117f1b4Smrg 49201e04c3fSmrg /* This possibly changes the target of a buffer allocated by 49301e04c3fSmrg * CreateQueries. Issue 39) in the ARB_direct_state_access extension states 49401e04c3fSmrg * the following: 49501e04c3fSmrg * 49601e04c3fSmrg * "CreateQueries adds a <target>, so strictly speaking the <target> 49701e04c3fSmrg * command isn't needed for BeginQuery/EndQuery, but in the end, this also 49801e04c3fSmrg * isn't a selector, so we decided not to change it." 49901e04c3fSmrg * 50001e04c3fSmrg * Updating the target of the query object should be acceptable, so let's 50101e04c3fSmrg * do that. 50201e04c3fSmrg */ 50301e04c3fSmrg 504c1f859d4Smrg q->Target = target; 5057117f1b4Smrg q->Active = GL_TRUE; 5067117f1b4Smrg q->Result = 0; 5077117f1b4Smrg q->Ready = GL_FALSE; 508af69d88dSmrg q->EverBound = GL_TRUE; 509af69d88dSmrg q->Stream = index; 5107117f1b4Smrg 5113464ebd5Sriastradh /* XXX should probably refcount query objects */ 5123464ebd5Sriastradh *bindpt = q; 5137117f1b4Smrg 514c1f859d4Smrg ctx->Driver.BeginQuery(ctx, q); 5157117f1b4Smrg} 5167117f1b4Smrg 5177117f1b4Smrg 518af69d88dSmrgvoid GLAPIENTRY 519af69d88dSmrg_mesa_EndQueryIndexed(GLenum target, GLuint index) 5207117f1b4Smrg{ 5213464ebd5Sriastradh struct gl_query_object *q, **bindpt; 5227117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 5237117f1b4Smrg 5243464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 525af69d88dSmrg _mesa_debug(ctx, "glEndQueryIndexed(%s, %u)\n", 52601e04c3fSmrg _mesa_enum_to_string(target), index); 5273464ebd5Sriastradh 528af69d88dSmrg if (!query_error_check_index(ctx, target, index)) 529af69d88dSmrg return; 5307117f1b4Smrg 531af69d88dSmrg FLUSH_VERTICES(ctx, 0); 532af69d88dSmrg 533af69d88dSmrg bindpt = get_query_binding_point(ctx, target, index); 5343464ebd5Sriastradh if (!bindpt) { 535af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glEndQuery{Indexed}(target)"); 5363464ebd5Sriastradh return; 5377117f1b4Smrg } 5387117f1b4Smrg 5393464ebd5Sriastradh /* XXX should probably refcount query objects */ 5403464ebd5Sriastradh q = *bindpt; 541af69d88dSmrg 542af69d88dSmrg /* Check for GL_ANY_SAMPLES_PASSED vs GL_SAMPLES_PASSED. */ 543af69d88dSmrg if (q && q->Target != target) { 544af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 545af69d88dSmrg "glEndQuery(target=%s with active query of target %s)", 54601e04c3fSmrg _mesa_enum_to_string(target), 54701e04c3fSmrg _mesa_enum_to_string(q->Target)); 548af69d88dSmrg return; 549af69d88dSmrg } 550af69d88dSmrg 5513464ebd5Sriastradh *bindpt = NULL; 5523464ebd5Sriastradh 5537117f1b4Smrg if (!q || !q->Active) { 5547117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 555af69d88dSmrg "glEndQuery{Indexed}(no matching glBeginQuery{Indexed})"); 5567117f1b4Smrg return; 5577117f1b4Smrg } 5587117f1b4Smrg 5597117f1b4Smrg q->Active = GL_FALSE; 560c1f859d4Smrg ctx->Driver.EndQuery(ctx, q); 5617117f1b4Smrg} 5627117f1b4Smrg 563af69d88dSmrgvoid GLAPIENTRY 564af69d88dSmrg_mesa_BeginQuery(GLenum target, GLuint id) 565af69d88dSmrg{ 566af69d88dSmrg _mesa_BeginQueryIndexed(target, 0, id); 567af69d88dSmrg} 5687117f1b4Smrg 569af69d88dSmrgvoid GLAPIENTRY 570af69d88dSmrg_mesa_EndQuery(GLenum target) 5717117f1b4Smrg{ 572af69d88dSmrg _mesa_EndQueryIndexed(target, 0); 573af69d88dSmrg} 574af69d88dSmrg 575af69d88dSmrgvoid GLAPIENTRY 576af69d88dSmrg_mesa_QueryCounter(GLuint id, GLenum target) 577af69d88dSmrg{ 578af69d88dSmrg struct gl_query_object *q; 5797117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 5807117f1b4Smrg 5813464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 582af69d88dSmrg _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id, 58301e04c3fSmrg _mesa_enum_to_string(target)); 584af69d88dSmrg 585af69d88dSmrg /* error checking */ 586af69d88dSmrg if (target != GL_TIMESTAMP) { 587af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)"); 588af69d88dSmrg return; 589af69d88dSmrg } 590af69d88dSmrg 591af69d88dSmrg if (id == 0) { 592af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)"); 593af69d88dSmrg return; 594af69d88dSmrg } 595af69d88dSmrg 596af69d88dSmrg q = _mesa_lookup_query_object(ctx, id); 597af69d88dSmrg if (!q) { 598af69d88dSmrg /* XXX the Core profile should throw INVALID_OPERATION here */ 599af69d88dSmrg 600af69d88dSmrg /* create new object */ 601af69d88dSmrg q = ctx->Driver.NewQueryObject(ctx, id); 602af69d88dSmrg if (!q) { 603af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter"); 604af69d88dSmrg return; 605af69d88dSmrg } 60601e04c3fSmrg _mesa_HashInsertLocked(ctx->Query.QueryObjects, id, q); 607af69d88dSmrg } 608af69d88dSmrg else { 609af69d88dSmrg if (q->Target && q->Target != GL_TIMESTAMP) { 610af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 611af69d88dSmrg "glQueryCounter(id has an invalid target)"); 612af69d88dSmrg return; 613af69d88dSmrg } 614af69d88dSmrg } 615af69d88dSmrg 616af69d88dSmrg if (q->Active) { 617af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)"); 618af69d88dSmrg return; 619af69d88dSmrg } 620af69d88dSmrg 62101e04c3fSmrg /* This possibly changes the target of a buffer allocated by 62201e04c3fSmrg * CreateQueries. Issue 39) in the ARB_direct_state_access extension states 62301e04c3fSmrg * the following: 62401e04c3fSmrg * 62501e04c3fSmrg * "CreateQueries adds a <target>, so strictly speaking the <target> 62601e04c3fSmrg * command isn't needed for BeginQuery/EndQuery, but in the end, this also 62701e04c3fSmrg * isn't a selector, so we decided not to change it." 62801e04c3fSmrg * 62901e04c3fSmrg * Updating the target of the query object should be acceptable, so let's 63001e04c3fSmrg * do that. 63101e04c3fSmrg */ 63201e04c3fSmrg 633af69d88dSmrg q->Target = target; 634af69d88dSmrg q->Result = 0; 635af69d88dSmrg q->Ready = GL_FALSE; 636af69d88dSmrg q->EverBound = GL_TRUE; 637af69d88dSmrg 638af69d88dSmrg if (ctx->Driver.QueryCounter) { 639af69d88dSmrg ctx->Driver.QueryCounter(ctx, q); 640af69d88dSmrg } else { 641af69d88dSmrg /* QueryCounter is implemented using EndQuery without BeginQuery 642af69d88dSmrg * in drivers. This is actually Direct3D and Gallium convention. 643af69d88dSmrg */ 644af69d88dSmrg ctx->Driver.EndQuery(ctx, q); 645af69d88dSmrg } 646af69d88dSmrg} 647af69d88dSmrg 648af69d88dSmrg 649af69d88dSmrgvoid GLAPIENTRY 650af69d88dSmrg_mesa_GetQueryIndexediv(GLenum target, GLuint index, GLenum pname, 651af69d88dSmrg GLint *params) 652af69d88dSmrg{ 653af69d88dSmrg struct gl_query_object *q = NULL, **bindpt = NULL; 654af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 655af69d88dSmrg 656af69d88dSmrg if (MESA_VERBOSE & VERBOSE_API) 657af69d88dSmrg _mesa_debug(ctx, "glGetQueryIndexediv(%s, %u, %s)\n", 65801e04c3fSmrg _mesa_enum_to_string(target), 659af69d88dSmrg index, 66001e04c3fSmrg _mesa_enum_to_string(pname)); 6613464ebd5Sriastradh 662af69d88dSmrg if (!query_error_check_index(ctx, target, index)) 6633464ebd5Sriastradh return; 664af69d88dSmrg 66501e04c3fSmrg /* From the GL_EXT_occlusion_query_boolean spec: 66601e04c3fSmrg * 66701e04c3fSmrg * "The error INVALID_ENUM is generated if GetQueryivEXT is called where 66801e04c3fSmrg * <pname> is not CURRENT_QUERY_EXT." 66901e04c3fSmrg * 67001e04c3fSmrg * Same rule is present also in ES 3.2 spec. 67101e04c3fSmrg */ 67201e04c3fSmrg if (_mesa_is_gles(ctx) && pname != GL_CURRENT_QUERY) { 67301e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivEXT(%s)", 67401e04c3fSmrg _mesa_enum_to_string(pname)); 67501e04c3fSmrg return; 67601e04c3fSmrg } 67701e04c3fSmrg 678af69d88dSmrg if (target == GL_TIMESTAMP) { 679af69d88dSmrg if (!ctx->Extensions.ARB_timer_query) { 680af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)"); 681af69d88dSmrg return; 682af69d88dSmrg } 6837117f1b4Smrg } 684af69d88dSmrg else { 685af69d88dSmrg bindpt = get_query_binding_point(ctx, target, index); 686af69d88dSmrg if (!bindpt) { 687af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(target)"); 688af69d88dSmrg return; 689af69d88dSmrg } 6907117f1b4Smrg 691af69d88dSmrg q = *bindpt; 692af69d88dSmrg } 6933464ebd5Sriastradh 6947117f1b4Smrg switch (pname) { 6957117f1b4Smrg case GL_QUERY_COUNTER_BITS_ARB: 696af69d88dSmrg switch (target) { 697af69d88dSmrg case GL_SAMPLES_PASSED: 698af69d88dSmrg *params = ctx->Const.QueryCounterBits.SamplesPassed; 699af69d88dSmrg break; 700af69d88dSmrg case GL_ANY_SAMPLES_PASSED: 70101e04c3fSmrg case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: 702af69d88dSmrg /* The minimum value of this is 1 if it's nonzero, and the value 703af69d88dSmrg * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more 704af69d88dSmrg * bits. 705af69d88dSmrg */ 706af69d88dSmrg *params = 1; 707af69d88dSmrg break; 708af69d88dSmrg case GL_TIME_ELAPSED: 709af69d88dSmrg *params = ctx->Const.QueryCounterBits.TimeElapsed; 710af69d88dSmrg break; 711af69d88dSmrg case GL_TIMESTAMP: 712af69d88dSmrg *params = ctx->Const.QueryCounterBits.Timestamp; 713af69d88dSmrg break; 714af69d88dSmrg case GL_PRIMITIVES_GENERATED: 715af69d88dSmrg *params = ctx->Const.QueryCounterBits.PrimitivesGenerated; 716af69d88dSmrg break; 717af69d88dSmrg case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 718af69d88dSmrg *params = ctx->Const.QueryCounterBits.PrimitivesWritten; 719af69d88dSmrg break; 72001e04c3fSmrg case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB: 72101e04c3fSmrg case GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB: 72201e04c3fSmrg /* The minimum value of this is 1 if it's nonzero, and the value 72301e04c3fSmrg * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more 72401e04c3fSmrg * bits. 72501e04c3fSmrg */ 72601e04c3fSmrg *params = 1; 72701e04c3fSmrg break; 72801e04c3fSmrg case GL_VERTICES_SUBMITTED_ARB: 72901e04c3fSmrg *params = ctx->Const.QueryCounterBits.VerticesSubmitted; 73001e04c3fSmrg break; 73101e04c3fSmrg case GL_PRIMITIVES_SUBMITTED_ARB: 73201e04c3fSmrg *params = ctx->Const.QueryCounterBits.PrimitivesSubmitted; 73301e04c3fSmrg break; 73401e04c3fSmrg case GL_VERTEX_SHADER_INVOCATIONS_ARB: 73501e04c3fSmrg *params = ctx->Const.QueryCounterBits.VsInvocations; 73601e04c3fSmrg break; 73701e04c3fSmrg case GL_TESS_CONTROL_SHADER_PATCHES_ARB: 73801e04c3fSmrg *params = ctx->Const.QueryCounterBits.TessPatches; 73901e04c3fSmrg break; 74001e04c3fSmrg case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB: 74101e04c3fSmrg *params = ctx->Const.QueryCounterBits.TessInvocations; 74201e04c3fSmrg break; 74301e04c3fSmrg case GL_GEOMETRY_SHADER_INVOCATIONS: 74401e04c3fSmrg *params = ctx->Const.QueryCounterBits.GsInvocations; 74501e04c3fSmrg break; 74601e04c3fSmrg case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB: 74701e04c3fSmrg *params = ctx->Const.QueryCounterBits.GsPrimitives; 74801e04c3fSmrg break; 74901e04c3fSmrg case GL_FRAGMENT_SHADER_INVOCATIONS_ARB: 75001e04c3fSmrg *params = ctx->Const.QueryCounterBits.FsInvocations; 75101e04c3fSmrg break; 75201e04c3fSmrg case GL_COMPUTE_SHADER_INVOCATIONS_ARB: 75301e04c3fSmrg *params = ctx->Const.QueryCounterBits.ComputeInvocations; 75401e04c3fSmrg break; 75501e04c3fSmrg case GL_CLIPPING_INPUT_PRIMITIVES_ARB: 75601e04c3fSmrg *params = ctx->Const.QueryCounterBits.ClInPrimitives; 75701e04c3fSmrg break; 75801e04c3fSmrg case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB: 75901e04c3fSmrg *params = ctx->Const.QueryCounterBits.ClOutPrimitives; 76001e04c3fSmrg break; 761af69d88dSmrg default: 762af69d88dSmrg _mesa_problem(ctx, 763af69d88dSmrg "Unknown target in glGetQueryIndexediv(target = %s)", 76401e04c3fSmrg _mesa_enum_to_string(target)); 765af69d88dSmrg *params = 0; 766af69d88dSmrg break; 767af69d88dSmrg } 7687117f1b4Smrg break; 7697117f1b4Smrg case GL_CURRENT_QUERY_ARB: 770af69d88dSmrg *params = (q && q->Target == target) ? q->Id : 0; 7717117f1b4Smrg break; 7727117f1b4Smrg default: 773af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(pname)"); 7747117f1b4Smrg return; 7757117f1b4Smrg } 7767117f1b4Smrg} 7777117f1b4Smrg 778af69d88dSmrgvoid GLAPIENTRY 779af69d88dSmrg_mesa_GetQueryiv(GLenum target, GLenum pname, GLint *params) 780af69d88dSmrg{ 781af69d88dSmrg _mesa_GetQueryIndexediv(target, 0, pname, params); 782af69d88dSmrg} 7837117f1b4Smrg 78401e04c3fSmrgstatic void 78501e04c3fSmrgget_query_object(struct gl_context *ctx, const char *func, 78601e04c3fSmrg GLuint id, GLenum pname, GLenum ptype, 78701e04c3fSmrg struct gl_buffer_object *buf, intptr_t offset) 7887117f1b4Smrg{ 7897117f1b4Smrg struct gl_query_object *q = NULL; 79001e04c3fSmrg uint64_t value; 7917117f1b4Smrg 7923464ebd5Sriastradh if (MESA_VERBOSE & VERBOSE_API) 79301e04c3fSmrg _mesa_debug(ctx, "%s(%u, %s)\n", func, id, 79401e04c3fSmrg _mesa_enum_to_string(pname)); 7953464ebd5Sriastradh 7967117f1b4Smrg if (id) 797cdc920a0Smrg q = _mesa_lookup_query_object(ctx, id); 7987117f1b4Smrg 79901e04c3fSmrg if (!q || q->Active || !q->EverBound) { 8007117f1b4Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 80101e04c3fSmrg "%s(id=%d is invalid or active)", func, id); 80201e04c3fSmrg return; 80301e04c3fSmrg } 80401e04c3fSmrg 80501e04c3fSmrg /* From GL_EXT_occlusion_query_boolean spec: 80601e04c3fSmrg * 80701e04c3fSmrg * "Accepted by the <pname> parameter of GetQueryObjectivEXT and 80801e04c3fSmrg * GetQueryObjectuivEXT: 80901e04c3fSmrg * 81001e04c3fSmrg * QUERY_RESULT_EXT 0x8866 81101e04c3fSmrg * QUERY_RESULT_AVAILABLE_EXT 0x8867" 81201e04c3fSmrg * 81301e04c3fSmrg * Same rule is present also in ES 3.2 spec. 81401e04c3fSmrg */ 81501e04c3fSmrg if (_mesa_is_gles(ctx) && 81601e04c3fSmrg (pname != GL_QUERY_RESULT && pname != GL_QUERY_RESULT_AVAILABLE)) { 81701e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(%s)", func, 81801e04c3fSmrg _mesa_enum_to_string(pname)); 8197117f1b4Smrg return; 8207117f1b4Smrg } 8217117f1b4Smrg 82201e04c3fSmrg if (buf && buf != ctx->Shared->NullBufferObj) { 82301e04c3fSmrg bool is_64bit = ptype == GL_INT64_ARB || 82401e04c3fSmrg ptype == GL_UNSIGNED_INT64_ARB; 82501e04c3fSmrg if (!ctx->Extensions.ARB_query_buffer_object) { 82601e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(not supported)", func); 82701e04c3fSmrg return; 82801e04c3fSmrg } 82901e04c3fSmrg if (buf->Size < offset + 4 * (is_64bit ? 2 : 1)) { 83001e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(out of bounds)", func); 83101e04c3fSmrg return; 83201e04c3fSmrg } 83301e04c3fSmrg 83401e04c3fSmrg if (offset < 0) { 83501e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset is negative)", func); 83601e04c3fSmrg return; 83701e04c3fSmrg } 83801e04c3fSmrg 83901e04c3fSmrg switch (pname) { 84001e04c3fSmrg case GL_QUERY_RESULT: 84101e04c3fSmrg case GL_QUERY_RESULT_NO_WAIT: 84201e04c3fSmrg case GL_QUERY_RESULT_AVAILABLE: 84301e04c3fSmrg case GL_QUERY_TARGET: 84401e04c3fSmrg ctx->Driver.StoreQueryResult(ctx, q, buf, offset, pname, ptype); 84501e04c3fSmrg return; 84601e04c3fSmrg } 84701e04c3fSmrg 84801e04c3fSmrg /* fall through to get error below */ 84901e04c3fSmrg } 85001e04c3fSmrg 8517117f1b4Smrg switch (pname) { 85201e04c3fSmrg case GL_QUERY_RESULT: 85301e04c3fSmrg if (!q->Ready) 85401e04c3fSmrg ctx->Driver.WaitQuery(ctx, q); 85501e04c3fSmrg value = q->Result; 85601e04c3fSmrg break; 85701e04c3fSmrg case GL_QUERY_RESULT_NO_WAIT: 85801e04c3fSmrg if (!ctx->Extensions.ARB_query_buffer_object) 85901e04c3fSmrg goto invalid_enum; 86001e04c3fSmrg ctx->Driver.CheckQuery(ctx, q); 86101e04c3fSmrg if (!q->Ready) 8627117f1b4Smrg return; 86301e04c3fSmrg value = q->Result; 86401e04c3fSmrg break; 86501e04c3fSmrg case GL_QUERY_RESULT_AVAILABLE: 86601e04c3fSmrg if (!q->Ready) 86701e04c3fSmrg ctx->Driver.CheckQuery(ctx, q); 86801e04c3fSmrg value = q->Ready; 86901e04c3fSmrg break; 87001e04c3fSmrg case GL_QUERY_TARGET: 87101e04c3fSmrg value = q->Target; 87201e04c3fSmrg break; 87301e04c3fSmrg default: 87401e04c3fSmrginvalid_enum: 87501e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=%s)", 87601e04c3fSmrg func, _mesa_enum_to_string(pname)); 87701e04c3fSmrg return; 87801e04c3fSmrg } 87901e04c3fSmrg 88001e04c3fSmrg switch (ptype) { 88101e04c3fSmrg case GL_INT: { 88201e04c3fSmrg GLint *param = (GLint *)offset; 88301e04c3fSmrg if (value > 0x7fffffff) 88401e04c3fSmrg *param = 0x7fffffff; 88501e04c3fSmrg else 88601e04c3fSmrg *param = value; 88701e04c3fSmrg break; 88801e04c3fSmrg } 88901e04c3fSmrg case GL_UNSIGNED_INT: { 89001e04c3fSmrg GLuint *param = (GLuint *)offset; 89101e04c3fSmrg if (value > 0xffffffff) 89201e04c3fSmrg *param = 0xffffffff; 89301e04c3fSmrg else 89401e04c3fSmrg *param = value; 89501e04c3fSmrg break; 89601e04c3fSmrg } 89701e04c3fSmrg case GL_INT64_ARB: 89801e04c3fSmrg case GL_UNSIGNED_INT64_ARB: { 89901e04c3fSmrg GLuint64EXT *param = (GLuint64EXT *)offset; 90001e04c3fSmrg *param = value; 90101e04c3fSmrg break; 9027117f1b4Smrg } 90301e04c3fSmrg default: 90401e04c3fSmrg unreachable("unexpected ptype"); 90501e04c3fSmrg } 90601e04c3fSmrg} 90701e04c3fSmrg 90801e04c3fSmrgvoid GLAPIENTRY 90901e04c3fSmrg_mesa_GetQueryObjectiv(GLuint id, GLenum pname, GLint *params) 91001e04c3fSmrg{ 91101e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 91201e04c3fSmrg 91301e04c3fSmrg get_query_object(ctx, "glGetQueryObjectiv", 91401e04c3fSmrg id, pname, GL_INT, ctx->QueryBuffer, (intptr_t)params); 9157117f1b4Smrg} 9167117f1b4Smrg 9177117f1b4Smrg 918af69d88dSmrgvoid GLAPIENTRY 919af69d88dSmrg_mesa_GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params) 9207117f1b4Smrg{ 9217117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 9227117f1b4Smrg 92301e04c3fSmrg get_query_object(ctx, "glGetQueryObjectuiv", 92401e04c3fSmrg id, pname, GL_UNSIGNED_INT, 92501e04c3fSmrg ctx->QueryBuffer, (intptr_t)params); 92601e04c3fSmrg} 9273464ebd5Sriastradh 9287117f1b4Smrg 92901e04c3fSmrg/** 93001e04c3fSmrg * New with GL_EXT_timer_query 93101e04c3fSmrg */ 93201e04c3fSmrgvoid GLAPIENTRY 93301e04c3fSmrg_mesa_GetQueryObjecti64v(GLuint id, GLenum pname, GLint64EXT *params) 93401e04c3fSmrg{ 93501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 9367117f1b4Smrg 93701e04c3fSmrg get_query_object(ctx, "glGetQueryObjecti64v", 93801e04c3fSmrg id, pname, GL_INT64_ARB, 93901e04c3fSmrg ctx->QueryBuffer, (intptr_t)params); 9407117f1b4Smrg} 9417117f1b4Smrg 9427117f1b4Smrg 9437117f1b4Smrg/** 9447117f1b4Smrg * New with GL_EXT_timer_query 9457117f1b4Smrg */ 946af69d88dSmrgvoid GLAPIENTRY 94701e04c3fSmrg_mesa_GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64EXT *params) 9487117f1b4Smrg{ 9497117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 9507117f1b4Smrg 95101e04c3fSmrg get_query_object(ctx, "glGetQueryObjectui64v", 95201e04c3fSmrg id, pname, GL_UNSIGNED_INT64_ARB, 95301e04c3fSmrg ctx->QueryBuffer, (intptr_t)params); 95401e04c3fSmrg} 9553464ebd5Sriastradh 95601e04c3fSmrg/** 95701e04c3fSmrg * New with GL_ARB_query_buffer_object 95801e04c3fSmrg */ 95901e04c3fSmrgvoid GLAPIENTRY 96001e04c3fSmrg_mesa_GetQueryBufferObjectiv(GLuint id, GLuint buffer, GLenum pname, 96101e04c3fSmrg GLintptr offset) 96201e04c3fSmrg{ 96301e04c3fSmrg struct gl_buffer_object *buf; 96401e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 9657117f1b4Smrg 96601e04c3fSmrg buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectiv"); 96701e04c3fSmrg if (!buf) 9687117f1b4Smrg return; 9697117f1b4Smrg 97001e04c3fSmrg get_query_object(ctx, "glGetQueryBufferObjectiv", 97101e04c3fSmrg id, pname, GL_INT, buf, offset); 9727117f1b4Smrg} 9737117f1b4Smrg 9747117f1b4Smrg 975af69d88dSmrgvoid GLAPIENTRY 97601e04c3fSmrg_mesa_GetQueryBufferObjectuiv(GLuint id, GLuint buffer, GLenum pname, 97701e04c3fSmrg GLintptr offset) 9787117f1b4Smrg{ 97901e04c3fSmrg struct gl_buffer_object *buf; 9807117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 9817117f1b4Smrg 98201e04c3fSmrg buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectuiv"); 98301e04c3fSmrg if (!buf) 98401e04c3fSmrg return; 9853464ebd5Sriastradh 98601e04c3fSmrg get_query_object(ctx, "glGetQueryBufferObjectuiv", 98701e04c3fSmrg id, pname, GL_UNSIGNED_INT, buf, offset); 98801e04c3fSmrg} 9897117f1b4Smrg 99001e04c3fSmrg 99101e04c3fSmrgvoid GLAPIENTRY 99201e04c3fSmrg_mesa_GetQueryBufferObjecti64v(GLuint id, GLuint buffer, GLenum pname, 99301e04c3fSmrg GLintptr offset) 99401e04c3fSmrg{ 99501e04c3fSmrg struct gl_buffer_object *buf; 99601e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 99701e04c3fSmrg 99801e04c3fSmrg buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjecti64v"); 99901e04c3fSmrg if (!buf) 10007117f1b4Smrg return; 10017117f1b4Smrg 100201e04c3fSmrg get_query_object(ctx, "glGetQueryBufferObjecti64v", 100301e04c3fSmrg id, pname, GL_INT64_ARB, buf, offset); 10047117f1b4Smrg} 10057117f1b4Smrg 100601e04c3fSmrg 100701e04c3fSmrgvoid GLAPIENTRY 100801e04c3fSmrg_mesa_GetQueryBufferObjectui64v(GLuint id, GLuint buffer, GLenum pname, 100901e04c3fSmrg GLintptr offset) 101001e04c3fSmrg{ 101101e04c3fSmrg struct gl_buffer_object *buf; 101201e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 101301e04c3fSmrg 101401e04c3fSmrg buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectui64v"); 101501e04c3fSmrg if (!buf) 101601e04c3fSmrg return; 101701e04c3fSmrg 101801e04c3fSmrg get_query_object(ctx, "glGetQueryBufferObjectui64v", 101901e04c3fSmrg id, pname, GL_UNSIGNED_INT64_ARB, buf, offset); 102001e04c3fSmrg} 102101e04c3fSmrg 102201e04c3fSmrg 10237117f1b4Smrg/** 10247117f1b4Smrg * Allocate/init the context state related to query objects. 10257117f1b4Smrg */ 10267117f1b4Smrgvoid 10273464ebd5Sriastradh_mesa_init_queryobj(struct gl_context *ctx) 10287117f1b4Smrg{ 10297117f1b4Smrg ctx->Query.QueryObjects = _mesa_NewHashTable(); 10307117f1b4Smrg ctx->Query.CurrentOcclusionObject = NULL; 1031af69d88dSmrg 1032af69d88dSmrg ctx->Const.QueryCounterBits.SamplesPassed = 64; 1033af69d88dSmrg ctx->Const.QueryCounterBits.TimeElapsed = 64; 1034af69d88dSmrg ctx->Const.QueryCounterBits.Timestamp = 64; 1035af69d88dSmrg ctx->Const.QueryCounterBits.PrimitivesGenerated = 64; 1036af69d88dSmrg ctx->Const.QueryCounterBits.PrimitivesWritten = 64; 103701e04c3fSmrg 103801e04c3fSmrg ctx->Const.QueryCounterBits.VerticesSubmitted = 64; 103901e04c3fSmrg ctx->Const.QueryCounterBits.PrimitivesSubmitted = 64; 104001e04c3fSmrg ctx->Const.QueryCounterBits.VsInvocations = 64; 104101e04c3fSmrg ctx->Const.QueryCounterBits.TessPatches = 64; 104201e04c3fSmrg ctx->Const.QueryCounterBits.TessInvocations = 64; 104301e04c3fSmrg ctx->Const.QueryCounterBits.GsInvocations = 64; 104401e04c3fSmrg ctx->Const.QueryCounterBits.GsPrimitives = 64; 104501e04c3fSmrg ctx->Const.QueryCounterBits.FsInvocations = 64; 104601e04c3fSmrg ctx->Const.QueryCounterBits.ComputeInvocations = 64; 104701e04c3fSmrg ctx->Const.QueryCounterBits.ClInPrimitives = 64; 104801e04c3fSmrg ctx->Const.QueryCounterBits.ClOutPrimitives = 64; 10497117f1b4Smrg} 10507117f1b4Smrg 10517117f1b4Smrg 10527117f1b4Smrg/** 10537117f1b4Smrg * Callback for deleting a query object. Called by _mesa_HashDeleteAll(). 10547117f1b4Smrg */ 10557117f1b4Smrgstatic void 10567117f1b4Smrgdelete_queryobj_cb(GLuint id, void *data, void *userData) 10577117f1b4Smrg{ 10587117f1b4Smrg struct gl_query_object *q= (struct gl_query_object *) data; 10593464ebd5Sriastradh struct gl_context *ctx = (struct gl_context *)userData; 1060c1f859d4Smrg ctx->Driver.DeleteQuery(ctx, q); 10617117f1b4Smrg} 10627117f1b4Smrg 10637117f1b4Smrg 10647117f1b4Smrg/** 10657117f1b4Smrg * Free the context state related to query objects. 10667117f1b4Smrg */ 10677117f1b4Smrgvoid 10683464ebd5Sriastradh_mesa_free_queryobj_data(struct gl_context *ctx) 10697117f1b4Smrg{ 1070c1f859d4Smrg _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx); 10717117f1b4Smrg _mesa_DeleteHashTable(ctx->Query.QueryObjects); 10727117f1b4Smrg} 1073