1848b8605Smrg/* 2848b8605Smrg * Mesa 3-D graphics library 3848b8605Smrg * 4848b8605Smrg * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 5848b8605Smrg * 6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7848b8605Smrg * copy of this software and associated documentation files (the "Software"), 8848b8605Smrg * to deal in the Software without restriction, including without limitation 9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 11848b8605Smrg * Software is furnished to do so, subject to the following conditions: 12848b8605Smrg * 13848b8605Smrg * The above copyright notice and this permission notice shall be included 14848b8605Smrg * in all copies or substantial portions of the Software. 15848b8605Smrg * 16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 23848b8605Smrg */ 24848b8605Smrg 25848b8605Smrg 26b8e80941Smrg#include "bufferobj.h" 27848b8605Smrg#include "glheader.h" 28848b8605Smrg#include "context.h" 29848b8605Smrg#include "enums.h" 30848b8605Smrg#include "hash.h" 31848b8605Smrg#include "imports.h" 32848b8605Smrg#include "queryobj.h" 33848b8605Smrg#include "mtypes.h" 34848b8605Smrg 35848b8605Smrg 36848b8605Smrg/** 37848b8605Smrg * Allocate a new query object. This is a fallback routine called via 38848b8605Smrg * ctx->Driver.NewQueryObject(). 39848b8605Smrg * \param ctx - rendering context 40848b8605Smrg * \param id - the new object's ID 41848b8605Smrg * \return pointer to new query_object object or NULL if out of memory. 42848b8605Smrg */ 43848b8605Smrgstatic struct gl_query_object * 44848b8605Smrg_mesa_new_query_object(struct gl_context *ctx, GLuint id) 45848b8605Smrg{ 46848b8605Smrg struct gl_query_object *q = CALLOC_STRUCT(gl_query_object); 47848b8605Smrg (void) ctx; 48848b8605Smrg if (q) { 49848b8605Smrg q->Id = id; 50848b8605Smrg q->Result = 0; 51848b8605Smrg q->Active = GL_FALSE; 52848b8605Smrg 53848b8605Smrg /* This is to satisfy the language of the specification: "In the initial 54848b8605Smrg * state of a query object, the result is available" (OpenGL 3.1 § 55848b8605Smrg * 2.13). 56848b8605Smrg */ 57848b8605Smrg q->Ready = GL_TRUE; 58848b8605Smrg 59848b8605Smrg /* OpenGL 3.1 § 2.13 says about GenQueries, "These names are marked as 60848b8605Smrg * used, but no object is associated with them until the first time they 61848b8605Smrg * are used by BeginQuery." Since our implementation actually does 62848b8605Smrg * allocate an object at this point, use a flag to indicate that this 63848b8605Smrg * object has not yet been bound so should not be considered a query. 64848b8605Smrg */ 65848b8605Smrg q->EverBound = GL_FALSE; 66848b8605Smrg } 67848b8605Smrg return q; 68848b8605Smrg} 69848b8605Smrg 70848b8605Smrg 71848b8605Smrg/** 72848b8605Smrg * Begin a query. Software driver fallback. 73848b8605Smrg * Called via ctx->Driver.BeginQuery(). 74848b8605Smrg */ 75848b8605Smrgstatic void 76848b8605Smrg_mesa_begin_query(struct gl_context *ctx, struct gl_query_object *q) 77848b8605Smrg{ 78848b8605Smrg ctx->NewState |= _NEW_DEPTH; /* for swrast */ 79848b8605Smrg} 80848b8605Smrg 81848b8605Smrg 82848b8605Smrg/** 83848b8605Smrg * End a query. Software driver fallback. 84848b8605Smrg * Called via ctx->Driver.EndQuery(). 85848b8605Smrg */ 86848b8605Smrgstatic void 87848b8605Smrg_mesa_end_query(struct gl_context *ctx, struct gl_query_object *q) 88848b8605Smrg{ 89848b8605Smrg ctx->NewState |= _NEW_DEPTH; /* for swrast */ 90848b8605Smrg q->Ready = GL_TRUE; 91848b8605Smrg} 92848b8605Smrg 93848b8605Smrg 94848b8605Smrg/** 95848b8605Smrg * Wait for query to complete. Software driver fallback. 96848b8605Smrg * Called via ctx->Driver.WaitQuery(). 97848b8605Smrg */ 98848b8605Smrgstatic void 99848b8605Smrg_mesa_wait_query(struct gl_context *ctx, struct gl_query_object *q) 100848b8605Smrg{ 101848b8605Smrg /* For software drivers, _mesa_end_query() should have completed the query. 102848b8605Smrg * For real hardware, implement a proper WaitQuery() driver function, 103848b8605Smrg * which may require issuing a flush. 104848b8605Smrg */ 105848b8605Smrg assert(q->Ready); 106848b8605Smrg} 107848b8605Smrg 108848b8605Smrg 109848b8605Smrg/** 110848b8605Smrg * Check if a query results are ready. Software driver fallback. 111848b8605Smrg * Called via ctx->Driver.CheckQuery(). 112848b8605Smrg */ 113848b8605Smrgstatic void 114848b8605Smrg_mesa_check_query(struct gl_context *ctx, struct gl_query_object *q) 115848b8605Smrg{ 116848b8605Smrg /* No-op for sw rendering. 117848b8605Smrg * HW drivers may need to flush at this time. 118848b8605Smrg */ 119848b8605Smrg} 120848b8605Smrg 121848b8605Smrg 122848b8605Smrg/** 123848b8605Smrg * Delete a query object. Called via ctx->Driver.DeleteQuery(). 124848b8605Smrg * Not removed from hash table here. 125848b8605Smrg */ 126848b8605Smrgstatic void 127848b8605Smrg_mesa_delete_query(struct gl_context *ctx, struct gl_query_object *q) 128848b8605Smrg{ 129848b8605Smrg free(q->Label); 130848b8605Smrg free(q); 131848b8605Smrg} 132848b8605Smrg 133848b8605Smrg 134848b8605Smrgvoid 135848b8605Smrg_mesa_init_query_object_functions(struct dd_function_table *driver) 136848b8605Smrg{ 137848b8605Smrg driver->NewQueryObject = _mesa_new_query_object; 138848b8605Smrg driver->DeleteQuery = _mesa_delete_query; 139848b8605Smrg driver->BeginQuery = _mesa_begin_query; 140848b8605Smrg driver->EndQuery = _mesa_end_query; 141848b8605Smrg driver->WaitQuery = _mesa_wait_query; 142848b8605Smrg driver->CheckQuery = _mesa_check_query; 143848b8605Smrg} 144848b8605Smrg 145b8e80941Smrgstatic struct gl_query_object ** 146b8e80941Smrgget_pipe_stats_binding_point(struct gl_context *ctx, 147b8e80941Smrg GLenum target) 148b8e80941Smrg{ 149b8e80941Smrg const int which = target - GL_VERTICES_SUBMITTED; 150b8e80941Smrg assert(which < MAX_PIPELINE_STATISTICS); 151b8e80941Smrg 152b8e80941Smrg if (!_mesa_has_ARB_pipeline_statistics_query(ctx)) 153b8e80941Smrg return NULL; 154b8e80941Smrg 155b8e80941Smrg return &ctx->Query.pipeline_stats[which]; 156b8e80941Smrg} 157848b8605Smrg 158848b8605Smrg/** 159848b8605Smrg * Return pointer to the query object binding point for the given target and 160848b8605Smrg * index. 161848b8605Smrg * \return NULL if invalid target, else the address of binding point 162848b8605Smrg */ 163848b8605Smrgstatic struct gl_query_object ** 164848b8605Smrgget_query_binding_point(struct gl_context *ctx, GLenum target, GLuint index) 165848b8605Smrg{ 166848b8605Smrg switch (target) { 167b8e80941Smrg case GL_SAMPLES_PASSED: 168b8e80941Smrg if (_mesa_has_ARB_occlusion_query(ctx) || 169b8e80941Smrg _mesa_has_ARB_occlusion_query2(ctx)) 170848b8605Smrg return &ctx->Query.CurrentOcclusionObject; 171848b8605Smrg else 172848b8605Smrg return NULL; 173848b8605Smrg case GL_ANY_SAMPLES_PASSED: 174b8e80941Smrg if (_mesa_has_ARB_occlusion_query2(ctx) || 175b8e80941Smrg _mesa_has_EXT_occlusion_query_boolean(ctx)) 176848b8605Smrg return &ctx->Query.CurrentOcclusionObject; 177848b8605Smrg else 178848b8605Smrg return NULL; 179848b8605Smrg case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: 180b8e80941Smrg if (_mesa_has_ARB_ES3_compatibility(ctx) || 181b8e80941Smrg _mesa_has_EXT_occlusion_query_boolean(ctx)) 182848b8605Smrg return &ctx->Query.CurrentOcclusionObject; 183848b8605Smrg else 184848b8605Smrg return NULL; 185b8e80941Smrg case GL_TIME_ELAPSED: 186b8e80941Smrg if (_mesa_has_EXT_timer_query(ctx) || 187b8e80941Smrg _mesa_has_EXT_disjoint_timer_query(ctx)) 188848b8605Smrg return &ctx->Query.CurrentTimerObject; 189848b8605Smrg else 190848b8605Smrg return NULL; 191848b8605Smrg case GL_PRIMITIVES_GENERATED: 192b8e80941Smrg if (_mesa_has_EXT_transform_feedback(ctx) || 193b8e80941Smrg _mesa_has_EXT_tessellation_shader(ctx) || 194b8e80941Smrg _mesa_has_OES_geometry_shader(ctx)) 195848b8605Smrg return &ctx->Query.PrimitivesGenerated[index]; 196848b8605Smrg else 197848b8605Smrg return NULL; 198848b8605Smrg case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 199b8e80941Smrg if (_mesa_has_EXT_transform_feedback(ctx) || _mesa_is_gles3(ctx)) 200848b8605Smrg return &ctx->Query.PrimitivesWritten[index]; 201848b8605Smrg else 202848b8605Smrg return NULL; 203b8e80941Smrg case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW: 204b8e80941Smrg if (_mesa_has_ARB_transform_feedback_overflow_query(ctx)) 205b8e80941Smrg return &ctx->Query.TransformFeedbackOverflow[index]; 206b8e80941Smrg else 207b8e80941Smrg return NULL; 208b8e80941Smrg case GL_TRANSFORM_FEEDBACK_OVERFLOW: 209b8e80941Smrg if (_mesa_has_ARB_transform_feedback_overflow_query(ctx)) 210b8e80941Smrg return &ctx->Query.TransformFeedbackOverflowAny; 211b8e80941Smrg else 212b8e80941Smrg return NULL; 213b8e80941Smrg 214b8e80941Smrg case GL_VERTICES_SUBMITTED: 215b8e80941Smrg case GL_PRIMITIVES_SUBMITTED: 216b8e80941Smrg case GL_VERTEX_SHADER_INVOCATIONS: 217b8e80941Smrg case GL_FRAGMENT_SHADER_INVOCATIONS: 218b8e80941Smrg case GL_CLIPPING_INPUT_PRIMITIVES: 219b8e80941Smrg case GL_CLIPPING_OUTPUT_PRIMITIVES: 220b8e80941Smrg return get_pipe_stats_binding_point(ctx, target); 221b8e80941Smrg 222b8e80941Smrg case GL_GEOMETRY_SHADER_INVOCATIONS: 223b8e80941Smrg /* GL_GEOMETRY_SHADER_INVOCATIONS is defined in a non-sequential order */ 224b8e80941Smrg target = GL_VERTICES_SUBMITTED + MAX_PIPELINE_STATISTICS - 1; 225b8e80941Smrg /* fallthrough */ 226b8e80941Smrg case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED: 227b8e80941Smrg if (_mesa_has_geometry_shaders(ctx)) 228b8e80941Smrg return get_pipe_stats_binding_point(ctx, target); 229b8e80941Smrg else 230b8e80941Smrg return NULL; 231b8e80941Smrg 232b8e80941Smrg case GL_TESS_CONTROL_SHADER_PATCHES: 233b8e80941Smrg case GL_TESS_EVALUATION_SHADER_INVOCATIONS: 234b8e80941Smrg if (_mesa_has_tessellation(ctx)) 235b8e80941Smrg return get_pipe_stats_binding_point(ctx, target); 236b8e80941Smrg else 237b8e80941Smrg return NULL; 238b8e80941Smrg 239b8e80941Smrg case GL_COMPUTE_SHADER_INVOCATIONS: 240b8e80941Smrg if (_mesa_has_compute_shaders(ctx)) 241b8e80941Smrg return get_pipe_stats_binding_point(ctx, target); 242b8e80941Smrg else 243b8e80941Smrg return NULL; 244b8e80941Smrg 245848b8605Smrg default: 246848b8605Smrg return NULL; 247848b8605Smrg } 248848b8605Smrg} 249848b8605Smrg 250b8e80941Smrg/** 251b8e80941Smrg * Create $n query objects and store them in *ids. Make them of type $target 252b8e80941Smrg * if dsa is set. Called from _mesa_GenQueries() and _mesa_CreateQueries(). 253b8e80941Smrg */ 254b8e80941Smrgstatic void 255b8e80941Smrgcreate_queries(struct gl_context *ctx, GLenum target, GLsizei n, GLuint *ids, 256b8e80941Smrg bool dsa) 257848b8605Smrg{ 258b8e80941Smrg const char *func = dsa ? "glGenQueries" : "glCreateQueries"; 259848b8605Smrg GLuint first; 260848b8605Smrg 261848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 262b8e80941Smrg _mesa_debug(ctx, "%s(%d)\n", func, n); 263848b8605Smrg 264848b8605Smrg if (n < 0) { 265b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func); 266848b8605Smrg return; 267848b8605Smrg } 268848b8605Smrg 269848b8605Smrg first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n); 270848b8605Smrg if (first) { 271848b8605Smrg GLsizei i; 272848b8605Smrg for (i = 0; i < n; i++) { 273848b8605Smrg struct gl_query_object *q 274848b8605Smrg = ctx->Driver.NewQueryObject(ctx, first + i); 275848b8605Smrg if (!q) { 276b8e80941Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); 277848b8605Smrg return; 278b8e80941Smrg } else if (dsa) { 279b8e80941Smrg /* Do the equivalent of binding the buffer with a target */ 280b8e80941Smrg q->Target = target; 281b8e80941Smrg q->EverBound = GL_TRUE; 282848b8605Smrg } 283848b8605Smrg ids[i] = first + i; 284b8e80941Smrg _mesa_HashInsertLocked(ctx->Query.QueryObjects, first + i, q); 285848b8605Smrg } 286848b8605Smrg } 287848b8605Smrg} 288848b8605Smrg 289b8e80941Smrgvoid GLAPIENTRY 290b8e80941Smrg_mesa_GenQueries(GLsizei n, GLuint *ids) 291b8e80941Smrg{ 292b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 293b8e80941Smrg create_queries(ctx, 0, n, ids, false); 294b8e80941Smrg} 295b8e80941Smrg 296b8e80941Smrgvoid GLAPIENTRY 297b8e80941Smrg_mesa_CreateQueries(GLenum target, GLsizei n, GLuint *ids) 298b8e80941Smrg{ 299b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 300b8e80941Smrg 301b8e80941Smrg switch (target) { 302b8e80941Smrg case GL_SAMPLES_PASSED: 303b8e80941Smrg case GL_ANY_SAMPLES_PASSED: 304b8e80941Smrg case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: 305b8e80941Smrg case GL_TIME_ELAPSED: 306b8e80941Smrg case GL_TIMESTAMP: 307b8e80941Smrg case GL_PRIMITIVES_GENERATED: 308b8e80941Smrg case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 309b8e80941Smrg case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW: 310b8e80941Smrg case GL_TRANSFORM_FEEDBACK_OVERFLOW: 311b8e80941Smrg break; 312b8e80941Smrg default: 313b8e80941Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glCreateQueries(invalid target = %s)", 314b8e80941Smrg _mesa_enum_to_string(target)); 315b8e80941Smrg return; 316b8e80941Smrg } 317b8e80941Smrg 318b8e80941Smrg create_queries(ctx, target, n, ids, true); 319b8e80941Smrg} 320b8e80941Smrg 321848b8605Smrg 322848b8605Smrgvoid GLAPIENTRY 323848b8605Smrg_mesa_DeleteQueries(GLsizei n, const GLuint *ids) 324848b8605Smrg{ 325848b8605Smrg GLint i; 326848b8605Smrg GET_CURRENT_CONTEXT(ctx); 327848b8605Smrg FLUSH_VERTICES(ctx, 0); 328848b8605Smrg 329848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 330848b8605Smrg _mesa_debug(ctx, "glDeleteQueries(%d)\n", n); 331848b8605Smrg 332848b8605Smrg if (n < 0) { 333848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)"); 334848b8605Smrg return; 335848b8605Smrg } 336848b8605Smrg 337848b8605Smrg for (i = 0; i < n; i++) { 338848b8605Smrg if (ids[i] > 0) { 339848b8605Smrg struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]); 340848b8605Smrg if (q) { 341848b8605Smrg if (q->Active) { 342848b8605Smrg struct gl_query_object **bindpt; 343848b8605Smrg bindpt = get_query_binding_point(ctx, q->Target, q->Stream); 344848b8605Smrg assert(bindpt); /* Should be non-null for active q. */ 345848b8605Smrg if (bindpt) { 346848b8605Smrg *bindpt = NULL; 347848b8605Smrg } 348848b8605Smrg q->Active = GL_FALSE; 349848b8605Smrg ctx->Driver.EndQuery(ctx, q); 350848b8605Smrg } 351b8e80941Smrg _mesa_HashRemoveLocked(ctx->Query.QueryObjects, ids[i]); 352848b8605Smrg ctx->Driver.DeleteQuery(ctx, q); 353848b8605Smrg } 354848b8605Smrg } 355848b8605Smrg } 356848b8605Smrg} 357848b8605Smrg 358848b8605Smrg 359848b8605SmrgGLboolean GLAPIENTRY 360848b8605Smrg_mesa_IsQuery(GLuint id) 361848b8605Smrg{ 362848b8605Smrg struct gl_query_object *q; 363848b8605Smrg 364848b8605Smrg GET_CURRENT_CONTEXT(ctx); 365848b8605Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 366848b8605Smrg 367848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 368848b8605Smrg _mesa_debug(ctx, "glIsQuery(%u)\n", id); 369848b8605Smrg 370848b8605Smrg if (id == 0) 371848b8605Smrg return GL_FALSE; 372848b8605Smrg 373848b8605Smrg q = _mesa_lookup_query_object(ctx, id); 374848b8605Smrg if (q == NULL) 375848b8605Smrg return GL_FALSE; 376848b8605Smrg 377848b8605Smrg return q->EverBound; 378848b8605Smrg} 379848b8605Smrg 380848b8605Smrgstatic GLboolean 381848b8605Smrgquery_error_check_index(struct gl_context *ctx, GLenum target, GLuint index) 382848b8605Smrg{ 383848b8605Smrg switch (target) { 384848b8605Smrg case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 385848b8605Smrg case GL_PRIMITIVES_GENERATED: 386b8e80941Smrg case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW: 387848b8605Smrg if (index >= ctx->Const.MaxVertexStreams) { 388848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 389848b8605Smrg "glBeginQueryIndexed(index>=MaxVertexStreams)"); 390848b8605Smrg return GL_FALSE; 391848b8605Smrg } 392848b8605Smrg break; 393848b8605Smrg default: 394848b8605Smrg if (index > 0) { 395848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glBeginQueryIndexed(index>0)"); 396848b8605Smrg return GL_FALSE; 397848b8605Smrg } 398848b8605Smrg } 399848b8605Smrg return GL_TRUE; 400848b8605Smrg} 401848b8605Smrg 402848b8605Smrgvoid GLAPIENTRY 403848b8605Smrg_mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id) 404848b8605Smrg{ 405848b8605Smrg struct gl_query_object *q, **bindpt; 406848b8605Smrg GET_CURRENT_CONTEXT(ctx); 407848b8605Smrg 408848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 409848b8605Smrg _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n", 410b8e80941Smrg _mesa_enum_to_string(target), index, id); 411848b8605Smrg 412848b8605Smrg if (!query_error_check_index(ctx, target, index)) 413848b8605Smrg return; 414848b8605Smrg 415848b8605Smrg FLUSH_VERTICES(ctx, 0); 416848b8605Smrg 417848b8605Smrg bindpt = get_query_binding_point(ctx, target, index); 418848b8605Smrg if (!bindpt) { 419848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)"); 420848b8605Smrg return; 421848b8605Smrg } 422848b8605Smrg 423848b8605Smrg /* From the GL_ARB_occlusion_query spec: 424848b8605Smrg * 425848b8605Smrg * "If BeginQueryARB is called while another query is already in 426848b8605Smrg * progress with the same target, an INVALID_OPERATION error is 427848b8605Smrg * generated." 428848b8605Smrg */ 429848b8605Smrg if (*bindpt) { 430848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 431848b8605Smrg "glBeginQuery{Indexed}(target=%s is active)", 432b8e80941Smrg _mesa_enum_to_string(target)); 433848b8605Smrg return; 434848b8605Smrg } 435848b8605Smrg 436848b8605Smrg if (id == 0) { 437848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)"); 438848b8605Smrg return; 439848b8605Smrg } 440848b8605Smrg 441848b8605Smrg q = _mesa_lookup_query_object(ctx, id); 442848b8605Smrg if (!q) { 443848b8605Smrg if (ctx->API != API_OPENGL_COMPAT) { 444848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 445848b8605Smrg "glBeginQuery{Indexed}(non-gen name)"); 446848b8605Smrg return; 447848b8605Smrg } else { 448848b8605Smrg /* create new object */ 449848b8605Smrg q = ctx->Driver.NewQueryObject(ctx, id); 450848b8605Smrg if (!q) { 451848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}"); 452848b8605Smrg return; 453848b8605Smrg } 454b8e80941Smrg _mesa_HashInsertLocked(ctx->Query.QueryObjects, id, q); 455848b8605Smrg } 456848b8605Smrg } 457848b8605Smrg else { 458848b8605Smrg /* pre-existing object */ 459848b8605Smrg if (q->Active) { 460848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 461848b8605Smrg "glBeginQuery{Indexed}(query already active)"); 462848b8605Smrg return; 463848b8605Smrg } 464b8e80941Smrg 465b8e80941Smrg /* Section 2.14 Asynchronous Queries, page 84 of the OpenGL ES 3.0.4 466b8e80941Smrg * spec states: 467b8e80941Smrg * 468b8e80941Smrg * "BeginQuery generates an INVALID_OPERATION error if any of the 469b8e80941Smrg * following conditions hold: [...] id is the name of an 470b8e80941Smrg * existing query object whose type does not match target; [...] 471b8e80941Smrg * 472b8e80941Smrg * Similar wording exists in the OpenGL 4.5 spec, section 4.2. QUERY 473b8e80941Smrg * OBJECTS AND ASYNCHRONOUS QUERIES, page 43. 474b8e80941Smrg */ 475b8e80941Smrg if (q->EverBound && q->Target != target) { 476b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 477b8e80941Smrg "glBeginQuery{Indexed}(target mismatch)"); 478b8e80941Smrg return; 479b8e80941Smrg } 480848b8605Smrg } 481848b8605Smrg 482b8e80941Smrg /* This possibly changes the target of a buffer allocated by 483b8e80941Smrg * CreateQueries. Issue 39) in the ARB_direct_state_access extension states 484b8e80941Smrg * the following: 485b8e80941Smrg * 486b8e80941Smrg * "CreateQueries adds a <target>, so strictly speaking the <target> 487b8e80941Smrg * command isn't needed for BeginQuery/EndQuery, but in the end, this also 488b8e80941Smrg * isn't a selector, so we decided not to change it." 489b8e80941Smrg * 490b8e80941Smrg * Updating the target of the query object should be acceptable, so let's 491b8e80941Smrg * do that. 492b8e80941Smrg */ 493b8e80941Smrg 494848b8605Smrg q->Target = target; 495848b8605Smrg q->Active = GL_TRUE; 496848b8605Smrg q->Result = 0; 497848b8605Smrg q->Ready = GL_FALSE; 498848b8605Smrg q->EverBound = GL_TRUE; 499848b8605Smrg q->Stream = index; 500848b8605Smrg 501848b8605Smrg /* XXX should probably refcount query objects */ 502848b8605Smrg *bindpt = q; 503848b8605Smrg 504848b8605Smrg ctx->Driver.BeginQuery(ctx, q); 505848b8605Smrg} 506848b8605Smrg 507848b8605Smrg 508848b8605Smrgvoid GLAPIENTRY 509848b8605Smrg_mesa_EndQueryIndexed(GLenum target, GLuint index) 510848b8605Smrg{ 511848b8605Smrg struct gl_query_object *q, **bindpt; 512848b8605Smrg GET_CURRENT_CONTEXT(ctx); 513848b8605Smrg 514848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 515848b8605Smrg _mesa_debug(ctx, "glEndQueryIndexed(%s, %u)\n", 516b8e80941Smrg _mesa_enum_to_string(target), index); 517848b8605Smrg 518848b8605Smrg if (!query_error_check_index(ctx, target, index)) 519848b8605Smrg return; 520848b8605Smrg 521848b8605Smrg FLUSH_VERTICES(ctx, 0); 522848b8605Smrg 523848b8605Smrg bindpt = get_query_binding_point(ctx, target, index); 524848b8605Smrg if (!bindpt) { 525848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glEndQuery{Indexed}(target)"); 526848b8605Smrg return; 527848b8605Smrg } 528848b8605Smrg 529848b8605Smrg /* XXX should probably refcount query objects */ 530848b8605Smrg q = *bindpt; 531848b8605Smrg 532848b8605Smrg /* Check for GL_ANY_SAMPLES_PASSED vs GL_SAMPLES_PASSED. */ 533848b8605Smrg if (q && q->Target != target) { 534848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 535848b8605Smrg "glEndQuery(target=%s with active query of target %s)", 536b8e80941Smrg _mesa_enum_to_string(target), 537b8e80941Smrg _mesa_enum_to_string(q->Target)); 538848b8605Smrg return; 539848b8605Smrg } 540848b8605Smrg 541848b8605Smrg *bindpt = NULL; 542848b8605Smrg 543848b8605Smrg if (!q || !q->Active) { 544848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 545848b8605Smrg "glEndQuery{Indexed}(no matching glBeginQuery{Indexed})"); 546848b8605Smrg return; 547848b8605Smrg } 548848b8605Smrg 549848b8605Smrg q->Active = GL_FALSE; 550848b8605Smrg ctx->Driver.EndQuery(ctx, q); 551848b8605Smrg} 552848b8605Smrg 553848b8605Smrgvoid GLAPIENTRY 554848b8605Smrg_mesa_BeginQuery(GLenum target, GLuint id) 555848b8605Smrg{ 556848b8605Smrg _mesa_BeginQueryIndexed(target, 0, id); 557848b8605Smrg} 558848b8605Smrg 559848b8605Smrgvoid GLAPIENTRY 560848b8605Smrg_mesa_EndQuery(GLenum target) 561848b8605Smrg{ 562848b8605Smrg _mesa_EndQueryIndexed(target, 0); 563848b8605Smrg} 564848b8605Smrg 565848b8605Smrgvoid GLAPIENTRY 566848b8605Smrg_mesa_QueryCounter(GLuint id, GLenum target) 567848b8605Smrg{ 568848b8605Smrg struct gl_query_object *q; 569848b8605Smrg GET_CURRENT_CONTEXT(ctx); 570848b8605Smrg 571848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 572848b8605Smrg _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id, 573b8e80941Smrg _mesa_enum_to_string(target)); 574848b8605Smrg 575848b8605Smrg /* error checking */ 576848b8605Smrg if (target != GL_TIMESTAMP) { 577848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)"); 578848b8605Smrg return; 579848b8605Smrg } 580848b8605Smrg 581848b8605Smrg if (id == 0) { 582848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)"); 583848b8605Smrg return; 584848b8605Smrg } 585848b8605Smrg 586848b8605Smrg q = _mesa_lookup_query_object(ctx, id); 587848b8605Smrg if (!q) { 588848b8605Smrg /* XXX the Core profile should throw INVALID_OPERATION here */ 589848b8605Smrg 590848b8605Smrg /* create new object */ 591848b8605Smrg q = ctx->Driver.NewQueryObject(ctx, id); 592848b8605Smrg if (!q) { 593848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter"); 594848b8605Smrg return; 595848b8605Smrg } 596b8e80941Smrg _mesa_HashInsertLocked(ctx->Query.QueryObjects, id, q); 597848b8605Smrg } 598848b8605Smrg else { 599848b8605Smrg if (q->Target && q->Target != GL_TIMESTAMP) { 600848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 601848b8605Smrg "glQueryCounter(id has an invalid target)"); 602848b8605Smrg return; 603848b8605Smrg } 604848b8605Smrg } 605848b8605Smrg 606848b8605Smrg if (q->Active) { 607848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)"); 608848b8605Smrg return; 609848b8605Smrg } 610848b8605Smrg 611b8e80941Smrg /* This possibly changes the target of a buffer allocated by 612b8e80941Smrg * CreateQueries. Issue 39) in the ARB_direct_state_access extension states 613b8e80941Smrg * the following: 614b8e80941Smrg * 615b8e80941Smrg * "CreateQueries adds a <target>, so strictly speaking the <target> 616b8e80941Smrg * command isn't needed for BeginQuery/EndQuery, but in the end, this also 617b8e80941Smrg * isn't a selector, so we decided not to change it." 618b8e80941Smrg * 619b8e80941Smrg * Updating the target of the query object should be acceptable, so let's 620b8e80941Smrg * do that. 621b8e80941Smrg */ 622b8e80941Smrg 623848b8605Smrg q->Target = target; 624848b8605Smrg q->Result = 0; 625848b8605Smrg q->Ready = GL_FALSE; 626848b8605Smrg q->EverBound = GL_TRUE; 627848b8605Smrg 628848b8605Smrg if (ctx->Driver.QueryCounter) { 629848b8605Smrg ctx->Driver.QueryCounter(ctx, q); 630848b8605Smrg } else { 631848b8605Smrg /* QueryCounter is implemented using EndQuery without BeginQuery 632848b8605Smrg * in drivers. This is actually Direct3D and Gallium convention. 633848b8605Smrg */ 634848b8605Smrg ctx->Driver.EndQuery(ctx, q); 635848b8605Smrg } 636848b8605Smrg} 637848b8605Smrg 638848b8605Smrg 639848b8605Smrgvoid GLAPIENTRY 640848b8605Smrg_mesa_GetQueryIndexediv(GLenum target, GLuint index, GLenum pname, 641848b8605Smrg GLint *params) 642848b8605Smrg{ 643848b8605Smrg struct gl_query_object *q = NULL, **bindpt = NULL; 644848b8605Smrg GET_CURRENT_CONTEXT(ctx); 645848b8605Smrg 646848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 647848b8605Smrg _mesa_debug(ctx, "glGetQueryIndexediv(%s, %u, %s)\n", 648b8e80941Smrg _mesa_enum_to_string(target), 649848b8605Smrg index, 650b8e80941Smrg _mesa_enum_to_string(pname)); 651848b8605Smrg 652848b8605Smrg if (!query_error_check_index(ctx, target, index)) 653848b8605Smrg return; 654848b8605Smrg 655b8e80941Smrg /* From the GL_EXT_occlusion_query_boolean spec: 656b8e80941Smrg * 657b8e80941Smrg * "The error INVALID_ENUM is generated if GetQueryivEXT is called where 658b8e80941Smrg * <pname> is not CURRENT_QUERY_EXT." 659b8e80941Smrg * 660b8e80941Smrg * Same rule is present also in ES 3.2 spec. 661b8e80941Smrg */ 662b8e80941Smrg if (_mesa_is_gles(ctx) && pname != GL_CURRENT_QUERY) { 663b8e80941Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivEXT(%s)", 664b8e80941Smrg _mesa_enum_to_string(pname)); 665b8e80941Smrg return; 666b8e80941Smrg } 667b8e80941Smrg 668848b8605Smrg if (target == GL_TIMESTAMP) { 669b8e80941Smrg if (!_mesa_has_ARB_timer_query(ctx) && 670b8e80941Smrg !_mesa_has_EXT_disjoint_timer_query(ctx)) { 671848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)"); 672848b8605Smrg return; 673848b8605Smrg } 674848b8605Smrg } 675848b8605Smrg else { 676848b8605Smrg bindpt = get_query_binding_point(ctx, target, index); 677848b8605Smrg if (!bindpt) { 678848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(target)"); 679848b8605Smrg return; 680848b8605Smrg } 681848b8605Smrg 682848b8605Smrg q = *bindpt; 683848b8605Smrg } 684848b8605Smrg 685848b8605Smrg switch (pname) { 686b8e80941Smrg case GL_QUERY_COUNTER_BITS: 687848b8605Smrg switch (target) { 688848b8605Smrg case GL_SAMPLES_PASSED: 689848b8605Smrg *params = ctx->Const.QueryCounterBits.SamplesPassed; 690848b8605Smrg break; 691848b8605Smrg case GL_ANY_SAMPLES_PASSED: 692b8e80941Smrg case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: 693848b8605Smrg /* The minimum value of this is 1 if it's nonzero, and the value 694848b8605Smrg * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more 695848b8605Smrg * bits. 696848b8605Smrg */ 697848b8605Smrg *params = 1; 698848b8605Smrg break; 699848b8605Smrg case GL_TIME_ELAPSED: 700848b8605Smrg *params = ctx->Const.QueryCounterBits.TimeElapsed; 701848b8605Smrg break; 702848b8605Smrg case GL_TIMESTAMP: 703848b8605Smrg *params = ctx->Const.QueryCounterBits.Timestamp; 704848b8605Smrg break; 705848b8605Smrg case GL_PRIMITIVES_GENERATED: 706848b8605Smrg *params = ctx->Const.QueryCounterBits.PrimitivesGenerated; 707848b8605Smrg break; 708848b8605Smrg case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 709848b8605Smrg *params = ctx->Const.QueryCounterBits.PrimitivesWritten; 710848b8605Smrg break; 711b8e80941Smrg case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW: 712b8e80941Smrg case GL_TRANSFORM_FEEDBACK_OVERFLOW: 713b8e80941Smrg /* The minimum value of this is 1 if it's nonzero, and the value 714b8e80941Smrg * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more 715b8e80941Smrg * bits. 716b8e80941Smrg */ 717b8e80941Smrg *params = 1; 718b8e80941Smrg break; 719b8e80941Smrg case GL_VERTICES_SUBMITTED: 720b8e80941Smrg *params = ctx->Const.QueryCounterBits.VerticesSubmitted; 721b8e80941Smrg break; 722b8e80941Smrg case GL_PRIMITIVES_SUBMITTED: 723b8e80941Smrg *params = ctx->Const.QueryCounterBits.PrimitivesSubmitted; 724b8e80941Smrg break; 725b8e80941Smrg case GL_VERTEX_SHADER_INVOCATIONS: 726b8e80941Smrg *params = ctx->Const.QueryCounterBits.VsInvocations; 727b8e80941Smrg break; 728b8e80941Smrg case GL_TESS_CONTROL_SHADER_PATCHES: 729b8e80941Smrg *params = ctx->Const.QueryCounterBits.TessPatches; 730b8e80941Smrg break; 731b8e80941Smrg case GL_TESS_EVALUATION_SHADER_INVOCATIONS: 732b8e80941Smrg *params = ctx->Const.QueryCounterBits.TessInvocations; 733b8e80941Smrg break; 734b8e80941Smrg case GL_GEOMETRY_SHADER_INVOCATIONS: 735b8e80941Smrg *params = ctx->Const.QueryCounterBits.GsInvocations; 736b8e80941Smrg break; 737b8e80941Smrg case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED: 738b8e80941Smrg *params = ctx->Const.QueryCounterBits.GsPrimitives; 739b8e80941Smrg break; 740b8e80941Smrg case GL_FRAGMENT_SHADER_INVOCATIONS: 741b8e80941Smrg *params = ctx->Const.QueryCounterBits.FsInvocations; 742b8e80941Smrg break; 743b8e80941Smrg case GL_COMPUTE_SHADER_INVOCATIONS: 744b8e80941Smrg *params = ctx->Const.QueryCounterBits.ComputeInvocations; 745b8e80941Smrg break; 746b8e80941Smrg case GL_CLIPPING_INPUT_PRIMITIVES: 747b8e80941Smrg *params = ctx->Const.QueryCounterBits.ClInPrimitives; 748b8e80941Smrg break; 749b8e80941Smrg case GL_CLIPPING_OUTPUT_PRIMITIVES: 750b8e80941Smrg *params = ctx->Const.QueryCounterBits.ClOutPrimitives; 751b8e80941Smrg break; 752848b8605Smrg default: 753848b8605Smrg _mesa_problem(ctx, 754848b8605Smrg "Unknown target in glGetQueryIndexediv(target = %s)", 755b8e80941Smrg _mesa_enum_to_string(target)); 756848b8605Smrg *params = 0; 757848b8605Smrg break; 758848b8605Smrg } 759848b8605Smrg break; 760b8e80941Smrg case GL_CURRENT_QUERY: 761848b8605Smrg *params = (q && q->Target == target) ? q->Id : 0; 762848b8605Smrg break; 763848b8605Smrg default: 764848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(pname)"); 765848b8605Smrg return; 766848b8605Smrg } 767848b8605Smrg} 768848b8605Smrg 769848b8605Smrgvoid GLAPIENTRY 770848b8605Smrg_mesa_GetQueryiv(GLenum target, GLenum pname, GLint *params) 771848b8605Smrg{ 772848b8605Smrg _mesa_GetQueryIndexediv(target, 0, pname, params); 773848b8605Smrg} 774848b8605Smrg 775b8e80941Smrgstatic void 776b8e80941Smrgget_query_object(struct gl_context *ctx, const char *func, 777b8e80941Smrg GLuint id, GLenum pname, GLenum ptype, 778b8e80941Smrg struct gl_buffer_object *buf, intptr_t offset) 779848b8605Smrg{ 780848b8605Smrg struct gl_query_object *q = NULL; 781b8e80941Smrg uint64_t value; 782848b8605Smrg 783848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 784b8e80941Smrg _mesa_debug(ctx, "%s(%u, %s)\n", func, id, 785b8e80941Smrg _mesa_enum_to_string(pname)); 786848b8605Smrg 787848b8605Smrg if (id) 788848b8605Smrg q = _mesa_lookup_query_object(ctx, id); 789848b8605Smrg 790b8e80941Smrg if (!q || q->Active || !q->EverBound) { 791848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 792b8e80941Smrg "%s(id=%d is invalid or active)", func, id); 793b8e80941Smrg return; 794b8e80941Smrg } 795b8e80941Smrg 796b8e80941Smrg /* From GL_EXT_occlusion_query_boolean spec: 797b8e80941Smrg * 798b8e80941Smrg * "Accepted by the <pname> parameter of GetQueryObjectivEXT and 799b8e80941Smrg * GetQueryObjectuivEXT: 800b8e80941Smrg * 801b8e80941Smrg * QUERY_RESULT_EXT 0x8866 802b8e80941Smrg * QUERY_RESULT_AVAILABLE_EXT 0x8867" 803b8e80941Smrg * 804b8e80941Smrg * Same rule is present also in ES 3.2 spec. 805b8e80941Smrg */ 806b8e80941Smrg if (_mesa_is_gles(ctx) && 807b8e80941Smrg (pname != GL_QUERY_RESULT && pname != GL_QUERY_RESULT_AVAILABLE)) { 808b8e80941Smrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(%s)", func, 809b8e80941Smrg _mesa_enum_to_string(pname)); 810848b8605Smrg return; 811848b8605Smrg } 812848b8605Smrg 813b8e80941Smrg if (buf && buf != ctx->Shared->NullBufferObj) { 814b8e80941Smrg bool is_64bit = ptype == GL_INT64_ARB || 815b8e80941Smrg ptype == GL_UNSIGNED_INT64_ARB; 816b8e80941Smrg if (!_mesa_has_ARB_query_buffer_object(ctx)) { 817b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(not supported)", func); 818b8e80941Smrg return; 819b8e80941Smrg } 820b8e80941Smrg if (buf->Size < offset + 4 * (is_64bit ? 2 : 1)) { 821b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(out of bounds)", func); 822b8e80941Smrg return; 823b8e80941Smrg } 824b8e80941Smrg 825b8e80941Smrg if (offset < 0) { 826b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset is negative)", func); 827b8e80941Smrg return; 828b8e80941Smrg } 829b8e80941Smrg 830b8e80941Smrg switch (pname) { 831b8e80941Smrg case GL_QUERY_RESULT: 832b8e80941Smrg case GL_QUERY_RESULT_NO_WAIT: 833b8e80941Smrg case GL_QUERY_RESULT_AVAILABLE: 834b8e80941Smrg case GL_QUERY_TARGET: 835b8e80941Smrg ctx->Driver.StoreQueryResult(ctx, q, buf, offset, pname, ptype); 836b8e80941Smrg return; 837b8e80941Smrg } 838b8e80941Smrg 839b8e80941Smrg /* fall through to get error below */ 840b8e80941Smrg } 841b8e80941Smrg 842848b8605Smrg switch (pname) { 843b8e80941Smrg case GL_QUERY_RESULT: 844b8e80941Smrg if (!q->Ready) 845b8e80941Smrg ctx->Driver.WaitQuery(ctx, q); 846b8e80941Smrg value = q->Result; 847b8e80941Smrg break; 848b8e80941Smrg case GL_QUERY_RESULT_NO_WAIT: 849b8e80941Smrg if (!_mesa_has_ARB_query_buffer_object(ctx)) 850b8e80941Smrg goto invalid_enum; 851b8e80941Smrg ctx->Driver.CheckQuery(ctx, q); 852b8e80941Smrg if (!q->Ready) 853848b8605Smrg return; 854b8e80941Smrg value = q->Result; 855b8e80941Smrg break; 856b8e80941Smrg case GL_QUERY_RESULT_AVAILABLE: 857b8e80941Smrg if (!q->Ready) 858b8e80941Smrg ctx->Driver.CheckQuery(ctx, q); 859b8e80941Smrg value = q->Ready; 860b8e80941Smrg break; 861b8e80941Smrg case GL_QUERY_TARGET: 862b8e80941Smrg value = q->Target; 863b8e80941Smrg break; 864b8e80941Smrg default: 865b8e80941Smrginvalid_enum: 866b8e80941Smrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=%s)", 867b8e80941Smrg func, _mesa_enum_to_string(pname)); 868b8e80941Smrg return; 869848b8605Smrg } 870b8e80941Smrg 871b8e80941Smrg switch (ptype) { 872b8e80941Smrg case GL_INT: { 873b8e80941Smrg GLint *param = (GLint *)offset; 874b8e80941Smrg if (value > 0x7fffffff) 875b8e80941Smrg *param = 0x7fffffff; 876b8e80941Smrg else 877b8e80941Smrg *param = value; 878b8e80941Smrg break; 879b8e80941Smrg } 880b8e80941Smrg case GL_UNSIGNED_INT: { 881b8e80941Smrg GLuint *param = (GLuint *)offset; 882b8e80941Smrg if (value > 0xffffffff) 883b8e80941Smrg *param = 0xffffffff; 884b8e80941Smrg else 885b8e80941Smrg *param = value; 886b8e80941Smrg break; 887b8e80941Smrg } 888b8e80941Smrg case GL_INT64_ARB: 889b8e80941Smrg case GL_UNSIGNED_INT64_ARB: { 890b8e80941Smrg GLuint64EXT *param = (GLuint64EXT *)offset; 891b8e80941Smrg *param = value; 892b8e80941Smrg break; 893b8e80941Smrg } 894b8e80941Smrg default: 895b8e80941Smrg unreachable("unexpected ptype"); 896b8e80941Smrg } 897b8e80941Smrg} 898b8e80941Smrg 899b8e80941Smrgvoid GLAPIENTRY 900b8e80941Smrg_mesa_GetQueryObjectiv(GLuint id, GLenum pname, GLint *params) 901b8e80941Smrg{ 902b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 903b8e80941Smrg 904b8e80941Smrg get_query_object(ctx, "glGetQueryObjectiv", 905b8e80941Smrg id, pname, GL_INT, ctx->QueryBuffer, (intptr_t)params); 906848b8605Smrg} 907848b8605Smrg 908848b8605Smrg 909848b8605Smrgvoid GLAPIENTRY 910848b8605Smrg_mesa_GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params) 911848b8605Smrg{ 912848b8605Smrg GET_CURRENT_CONTEXT(ctx); 913848b8605Smrg 914b8e80941Smrg get_query_object(ctx, "glGetQueryObjectuiv", 915b8e80941Smrg id, pname, GL_UNSIGNED_INT, 916b8e80941Smrg ctx->QueryBuffer, (intptr_t)params); 917b8e80941Smrg} 918848b8605Smrg 919848b8605Smrg 920b8e80941Smrg/** 921b8e80941Smrg * New with GL_EXT_timer_query 922b8e80941Smrg */ 923b8e80941Smrgvoid GLAPIENTRY 924b8e80941Smrg_mesa_GetQueryObjecti64v(GLuint id, GLenum pname, GLint64EXT *params) 925b8e80941Smrg{ 926b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 927848b8605Smrg 928b8e80941Smrg get_query_object(ctx, "glGetQueryObjecti64v", 929b8e80941Smrg id, pname, GL_INT64_ARB, 930b8e80941Smrg ctx->QueryBuffer, (intptr_t)params); 931848b8605Smrg} 932848b8605Smrg 933848b8605Smrg 934848b8605Smrg/** 935848b8605Smrg * New with GL_EXT_timer_query 936848b8605Smrg */ 937848b8605Smrgvoid GLAPIENTRY 938b8e80941Smrg_mesa_GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64EXT *params) 939848b8605Smrg{ 940848b8605Smrg GET_CURRENT_CONTEXT(ctx); 941848b8605Smrg 942b8e80941Smrg get_query_object(ctx, "glGetQueryObjectui64v", 943b8e80941Smrg id, pname, GL_UNSIGNED_INT64_ARB, 944b8e80941Smrg ctx->QueryBuffer, (intptr_t)params); 945b8e80941Smrg} 946848b8605Smrg 947b8e80941Smrg/** 948b8e80941Smrg * New with GL_ARB_query_buffer_object 949b8e80941Smrg */ 950b8e80941Smrgvoid GLAPIENTRY 951b8e80941Smrg_mesa_GetQueryBufferObjectiv(GLuint id, GLuint buffer, GLenum pname, 952b8e80941Smrg GLintptr offset) 953b8e80941Smrg{ 954b8e80941Smrg struct gl_buffer_object *buf; 955b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 956848b8605Smrg 957b8e80941Smrg buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectiv"); 958b8e80941Smrg if (!buf) 959848b8605Smrg return; 960848b8605Smrg 961b8e80941Smrg get_query_object(ctx, "glGetQueryBufferObjectiv", 962b8e80941Smrg id, pname, GL_INT, buf, offset); 963848b8605Smrg} 964848b8605Smrg 965848b8605Smrg 966848b8605Smrgvoid GLAPIENTRY 967b8e80941Smrg_mesa_GetQueryBufferObjectuiv(GLuint id, GLuint buffer, GLenum pname, 968b8e80941Smrg GLintptr offset) 969848b8605Smrg{ 970b8e80941Smrg struct gl_buffer_object *buf; 971848b8605Smrg GET_CURRENT_CONTEXT(ctx); 972848b8605Smrg 973b8e80941Smrg buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectuiv"); 974b8e80941Smrg if (!buf) 975b8e80941Smrg return; 976848b8605Smrg 977b8e80941Smrg get_query_object(ctx, "glGetQueryBufferObjectuiv", 978b8e80941Smrg id, pname, GL_UNSIGNED_INT, buf, offset); 979b8e80941Smrg} 980848b8605Smrg 981b8e80941Smrg 982b8e80941Smrgvoid GLAPIENTRY 983b8e80941Smrg_mesa_GetQueryBufferObjecti64v(GLuint id, GLuint buffer, GLenum pname, 984b8e80941Smrg GLintptr offset) 985b8e80941Smrg{ 986b8e80941Smrg struct gl_buffer_object *buf; 987b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 988b8e80941Smrg 989b8e80941Smrg buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjecti64v"); 990b8e80941Smrg if (!buf) 991848b8605Smrg return; 992848b8605Smrg 993b8e80941Smrg get_query_object(ctx, "glGetQueryBufferObjecti64v", 994b8e80941Smrg id, pname, GL_INT64_ARB, buf, offset); 995848b8605Smrg} 996848b8605Smrg 997b8e80941Smrg 998b8e80941Smrgvoid GLAPIENTRY 999b8e80941Smrg_mesa_GetQueryBufferObjectui64v(GLuint id, GLuint buffer, GLenum pname, 1000b8e80941Smrg GLintptr offset) 1001b8e80941Smrg{ 1002b8e80941Smrg struct gl_buffer_object *buf; 1003b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 1004b8e80941Smrg 1005b8e80941Smrg buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectui64v"); 1006b8e80941Smrg if (!buf) 1007b8e80941Smrg return; 1008b8e80941Smrg 1009b8e80941Smrg get_query_object(ctx, "glGetQueryBufferObjectui64v", 1010b8e80941Smrg id, pname, GL_UNSIGNED_INT64_ARB, buf, offset); 1011b8e80941Smrg} 1012b8e80941Smrg 1013b8e80941Smrg 1014848b8605Smrg/** 1015848b8605Smrg * Allocate/init the context state related to query objects. 1016848b8605Smrg */ 1017848b8605Smrgvoid 1018848b8605Smrg_mesa_init_queryobj(struct gl_context *ctx) 1019848b8605Smrg{ 1020848b8605Smrg ctx->Query.QueryObjects = _mesa_NewHashTable(); 1021848b8605Smrg ctx->Query.CurrentOcclusionObject = NULL; 1022848b8605Smrg 1023848b8605Smrg ctx->Const.QueryCounterBits.SamplesPassed = 64; 1024848b8605Smrg ctx->Const.QueryCounterBits.TimeElapsed = 64; 1025848b8605Smrg ctx->Const.QueryCounterBits.Timestamp = 64; 1026848b8605Smrg ctx->Const.QueryCounterBits.PrimitivesGenerated = 64; 1027848b8605Smrg ctx->Const.QueryCounterBits.PrimitivesWritten = 64; 1028b8e80941Smrg 1029b8e80941Smrg ctx->Const.QueryCounterBits.VerticesSubmitted = 64; 1030b8e80941Smrg ctx->Const.QueryCounterBits.PrimitivesSubmitted = 64; 1031b8e80941Smrg ctx->Const.QueryCounterBits.VsInvocations = 64; 1032b8e80941Smrg ctx->Const.QueryCounterBits.TessPatches = 64; 1033b8e80941Smrg ctx->Const.QueryCounterBits.TessInvocations = 64; 1034b8e80941Smrg ctx->Const.QueryCounterBits.GsInvocations = 64; 1035b8e80941Smrg ctx->Const.QueryCounterBits.GsPrimitives = 64; 1036b8e80941Smrg ctx->Const.QueryCounterBits.FsInvocations = 64; 1037b8e80941Smrg ctx->Const.QueryCounterBits.ComputeInvocations = 64; 1038b8e80941Smrg ctx->Const.QueryCounterBits.ClInPrimitives = 64; 1039b8e80941Smrg ctx->Const.QueryCounterBits.ClOutPrimitives = 64; 1040848b8605Smrg} 1041848b8605Smrg 1042848b8605Smrg 1043848b8605Smrg/** 1044848b8605Smrg * Callback for deleting a query object. Called by _mesa_HashDeleteAll(). 1045848b8605Smrg */ 1046848b8605Smrgstatic void 1047848b8605Smrgdelete_queryobj_cb(GLuint id, void *data, void *userData) 1048848b8605Smrg{ 1049848b8605Smrg struct gl_query_object *q= (struct gl_query_object *) data; 1050848b8605Smrg struct gl_context *ctx = (struct gl_context *)userData; 1051848b8605Smrg ctx->Driver.DeleteQuery(ctx, q); 1052848b8605Smrg} 1053848b8605Smrg 1054848b8605Smrg 1055848b8605Smrg/** 1056848b8605Smrg * Free the context state related to query objects. 1057848b8605Smrg */ 1058848b8605Smrgvoid 1059848b8605Smrg_mesa_free_queryobj_data(struct gl_context *ctx) 1060848b8605Smrg{ 1061848b8605Smrg _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx); 1062848b8605Smrg _mesa_DeleteHashTable(ctx->Query.QueryObjects); 1063848b8605Smrg} 1064