1/************************************************************************** 2 * 3 * Copyright 2007 VMware, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28 29/** 30 * glBegin/EndQuery interface to pipe 31 * 32 * \author Brian Paul 33 */ 34 35 36#include "util/compiler.h" 37#include "main/context.h" 38#include "main/queryobj.h" 39 40#include "pipe/p_context.h" 41#include "pipe/p_defines.h" 42#include "pipe/p_screen.h" 43#include "util/u_inlines.h" 44#include "st_context.h" 45#include "st_cb_queryobj.h" 46#include "st_cb_bitmap.h" 47#include "st_cb_bufferobjects.h" 48#include "st_util.h" 49 50 51static struct gl_query_object * 52st_NewQueryObject(struct gl_context *ctx, GLuint id) 53{ 54 struct st_query_object *stq = ST_CALLOC_STRUCT(st_query_object); 55 if (stq) { 56 stq->base.Id = id; 57 stq->base.Ready = GL_TRUE; 58 stq->pq = NULL; 59 stq->type = PIPE_QUERY_TYPES; /* an invalid value */ 60 return &stq->base; 61 } 62 return NULL; 63} 64 65 66static void 67free_queries(struct pipe_context *pipe, struct st_query_object *stq) 68{ 69 if (stq->pq) { 70 pipe->destroy_query(pipe, stq->pq); 71 stq->pq = NULL; 72 } 73 74 if (stq->pq_begin) { 75 pipe->destroy_query(pipe, stq->pq_begin); 76 stq->pq_begin = NULL; 77 } 78} 79 80 81static void 82st_DeleteQuery(struct gl_context *ctx, struct gl_query_object *q) 83{ 84 struct pipe_context *pipe = st_context(ctx)->pipe; 85 struct st_query_object *stq = st_query_object(q); 86 87 free_queries(pipe, stq); 88 89 _mesa_delete_query(ctx, q); 90} 91 92static int 93target_to_index(const struct st_context *st, const struct gl_query_object *q) 94{ 95 if (q->Target == GL_PRIMITIVES_GENERATED || 96 q->Target == GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN || 97 q->Target == GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB) 98 return q->Stream; 99 100 if (st->has_single_pipe_stat) { 101 switch (q->Target) { 102 case GL_VERTICES_SUBMITTED_ARB: 103 return PIPE_STAT_QUERY_IA_VERTICES; 104 case GL_PRIMITIVES_SUBMITTED_ARB: 105 return PIPE_STAT_QUERY_IA_PRIMITIVES; 106 case GL_VERTEX_SHADER_INVOCATIONS_ARB: 107 return PIPE_STAT_QUERY_VS_INVOCATIONS; 108 case GL_GEOMETRY_SHADER_INVOCATIONS: 109 return PIPE_STAT_QUERY_GS_INVOCATIONS; 110 case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB: 111 return PIPE_STAT_QUERY_GS_PRIMITIVES; 112 case GL_CLIPPING_INPUT_PRIMITIVES_ARB: 113 return PIPE_STAT_QUERY_C_INVOCATIONS; 114 case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB: 115 return PIPE_STAT_QUERY_C_PRIMITIVES; 116 case GL_FRAGMENT_SHADER_INVOCATIONS_ARB: 117 return PIPE_STAT_QUERY_PS_INVOCATIONS; 118 case GL_TESS_CONTROL_SHADER_PATCHES_ARB: 119 return PIPE_STAT_QUERY_HS_INVOCATIONS; 120 case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB: 121 return PIPE_STAT_QUERY_DS_INVOCATIONS; 122 case GL_COMPUTE_SHADER_INVOCATIONS_ARB: 123 return PIPE_STAT_QUERY_CS_INVOCATIONS; 124 default: 125 break; 126 } 127 } 128 129 return 0; 130} 131 132static void 133st_BeginQuery(struct gl_context *ctx, struct gl_query_object *q) 134{ 135 struct st_context *st = st_context(ctx); 136 struct pipe_context *pipe = st->pipe; 137 struct st_query_object *stq = st_query_object(q); 138 unsigned type; 139 bool ret = false; 140 141 st_flush_bitmap_cache(st_context(ctx)); 142 143 /* convert GL query type to Gallium query type */ 144 switch (q->Target) { 145 case GL_ANY_SAMPLES_PASSED: 146 type = PIPE_QUERY_OCCLUSION_PREDICATE; 147 break; 148 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: 149 type = PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE; 150 break; 151 case GL_SAMPLES_PASSED_ARB: 152 type = PIPE_QUERY_OCCLUSION_COUNTER; 153 break; 154 case GL_PRIMITIVES_GENERATED: 155 type = PIPE_QUERY_PRIMITIVES_GENERATED; 156 break; 157 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 158 type = PIPE_QUERY_PRIMITIVES_EMITTED; 159 break; 160 case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB: 161 type = PIPE_QUERY_SO_OVERFLOW_PREDICATE; 162 break; 163 case GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB: 164 type = PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE; 165 break; 166 case GL_TIME_ELAPSED: 167 if (st->has_time_elapsed) 168 type = PIPE_QUERY_TIME_ELAPSED; 169 else 170 type = PIPE_QUERY_TIMESTAMP; 171 break; 172 case GL_VERTICES_SUBMITTED_ARB: 173 case GL_PRIMITIVES_SUBMITTED_ARB: 174 case GL_VERTEX_SHADER_INVOCATIONS_ARB: 175 case GL_TESS_CONTROL_SHADER_PATCHES_ARB: 176 case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB: 177 case GL_GEOMETRY_SHADER_INVOCATIONS: 178 case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB: 179 case GL_FRAGMENT_SHADER_INVOCATIONS_ARB: 180 case GL_COMPUTE_SHADER_INVOCATIONS_ARB: 181 case GL_CLIPPING_INPUT_PRIMITIVES_ARB: 182 case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB: 183 type = st->has_single_pipe_stat ? PIPE_QUERY_PIPELINE_STATISTICS_SINGLE 184 : PIPE_QUERY_PIPELINE_STATISTICS; 185 break; 186 default: 187 assert(0 && "unexpected query target in st_BeginQuery()"); 188 return; 189 } 190 191 if (stq->type != type) { 192 /* free old query of different type */ 193 free_queries(pipe, stq); 194 stq->type = PIPE_QUERY_TYPES; /* an invalid value */ 195 } 196 197 if (q->Target == GL_TIME_ELAPSED && 198 type == PIPE_QUERY_TIMESTAMP) { 199 /* Determine time elapsed by emitting two timestamp queries. */ 200 if (!stq->pq_begin) { 201 stq->pq_begin = pipe->create_query(pipe, type, 0); 202 stq->type = type; 203 } 204 if (stq->pq_begin) 205 ret = pipe->end_query(pipe, stq->pq_begin); 206 } else { 207 if (!stq->pq) { 208 stq->pq = pipe->create_query(pipe, type, target_to_index(st, q)); 209 stq->type = type; 210 } 211 if (stq->pq) 212 ret = pipe->begin_query(pipe, stq->pq); 213 } 214 215 if (!ret) { 216 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery"); 217 218 free_queries(pipe, stq); 219 q->Active = GL_FALSE; 220 return; 221 } 222 223 if (stq->type != PIPE_QUERY_TIMESTAMP) 224 st->active_queries++; 225 226 assert(stq->type == type); 227} 228 229 230static void 231st_EndQuery(struct gl_context *ctx, struct gl_query_object *q) 232{ 233 struct st_context *st = st_context(ctx); 234 struct pipe_context *pipe = st->pipe; 235 struct st_query_object *stq = st_query_object(q); 236 bool ret = false; 237 238 st_flush_bitmap_cache(st_context(ctx)); 239 240 if ((q->Target == GL_TIMESTAMP || 241 q->Target == GL_TIME_ELAPSED) && 242 !stq->pq) { 243 stq->pq = pipe->create_query(pipe, PIPE_QUERY_TIMESTAMP, 0); 244 stq->type = PIPE_QUERY_TIMESTAMP; 245 } 246 247 if (stq->pq) 248 ret = pipe->end_query(pipe, stq->pq); 249 250 if (!ret) { 251 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glEndQuery"); 252 return; 253 } 254 255 if (stq->type != PIPE_QUERY_TIMESTAMP) 256 st->active_queries--; 257} 258 259 260static boolean 261get_query_result(struct pipe_context *pipe, 262 struct st_query_object *stq, 263 boolean wait) 264{ 265 union pipe_query_result data; 266 267 if (!stq->pq) { 268 /* Only needed in case we failed to allocate the gallium query earlier. 269 * Return TRUE so we don't spin on this forever. 270 */ 271 return TRUE; 272 } 273 274 if (!pipe->get_query_result(pipe, stq->pq, wait, &data)) 275 return FALSE; 276 277 switch (stq->type) { 278 case PIPE_QUERY_PIPELINE_STATISTICS: 279 switch (stq->base.Target) { 280 case GL_VERTICES_SUBMITTED_ARB: 281 stq->base.Result = data.pipeline_statistics.ia_vertices; 282 break; 283 case GL_PRIMITIVES_SUBMITTED_ARB: 284 stq->base.Result = data.pipeline_statistics.ia_primitives; 285 break; 286 case GL_VERTEX_SHADER_INVOCATIONS_ARB: 287 stq->base.Result = data.pipeline_statistics.vs_invocations; 288 break; 289 case GL_TESS_CONTROL_SHADER_PATCHES_ARB: 290 stq->base.Result = data.pipeline_statistics.hs_invocations; 291 break; 292 case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB: 293 stq->base.Result = data.pipeline_statistics.ds_invocations; 294 break; 295 case GL_GEOMETRY_SHADER_INVOCATIONS: 296 stq->base.Result = data.pipeline_statistics.gs_invocations; 297 break; 298 case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB: 299 stq->base.Result = data.pipeline_statistics.gs_primitives; 300 break; 301 case GL_FRAGMENT_SHADER_INVOCATIONS_ARB: 302 stq->base.Result = data.pipeline_statistics.ps_invocations; 303 break; 304 case GL_COMPUTE_SHADER_INVOCATIONS_ARB: 305 stq->base.Result = data.pipeline_statistics.cs_invocations; 306 break; 307 case GL_CLIPPING_INPUT_PRIMITIVES_ARB: 308 stq->base.Result = data.pipeline_statistics.c_invocations; 309 break; 310 case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB: 311 stq->base.Result = data.pipeline_statistics.c_primitives; 312 break; 313 default: 314 unreachable("invalid pipeline statistics counter"); 315 } 316 break; 317 case PIPE_QUERY_OCCLUSION_PREDICATE: 318 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 319 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: 320 case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE: 321 stq->base.Result = !!data.b; 322 break; 323 default: 324 stq->base.Result = data.u64; 325 break; 326 } 327 328 if (stq->base.Target == GL_TIME_ELAPSED && 329 stq->type == PIPE_QUERY_TIMESTAMP) { 330 /* Calculate the elapsed time from the two timestamp queries */ 331 GLuint64EXT Result0 = 0; 332 assert(stq->pq_begin); 333 pipe->get_query_result(pipe, stq->pq_begin, TRUE, (void *)&Result0); 334 stq->base.Result -= Result0; 335 } else { 336 assert(!stq->pq_begin); 337 } 338 339 return TRUE; 340} 341 342 343static void 344st_WaitQuery(struct gl_context *ctx, struct gl_query_object *q) 345{ 346 struct pipe_context *pipe = st_context(ctx)->pipe; 347 struct st_query_object *stq = st_query_object(q); 348 349 /* this function should only be called if we don't have a ready result */ 350 assert(!stq->base.Ready); 351 352 while (!stq->base.Ready && 353 !get_query_result(pipe, stq, TRUE)) 354 { 355 /* nothing */ 356 } 357 358 q->Ready = GL_TRUE; 359} 360 361 362static void 363st_CheckQuery(struct gl_context *ctx, struct gl_query_object *q) 364{ 365 struct pipe_context *pipe = st_context(ctx)->pipe; 366 struct st_query_object *stq = st_query_object(q); 367 assert(!q->Ready); /* we should not get called if Ready is TRUE */ 368 q->Ready = get_query_result(pipe, stq, FALSE); 369} 370 371 372static uint64_t 373st_GetTimestamp(struct gl_context *ctx) 374{ 375 struct pipe_context *pipe = st_context(ctx)->pipe; 376 struct pipe_screen *screen = st_context(ctx)->screen; 377 378 /* Prefer the per-screen function */ 379 if (screen->get_timestamp) { 380 return screen->get_timestamp(screen); 381 } 382 else { 383 /* Fall back to the per-context function */ 384 assert(pipe->get_timestamp); 385 return pipe->get_timestamp(pipe); 386 } 387} 388 389static void 390st_StoreQueryResult(struct gl_context *ctx, struct gl_query_object *q, 391 struct gl_buffer_object *buf, intptr_t offset, 392 GLenum pname, GLenum ptype) 393{ 394 struct pipe_context *pipe = st_context(ctx)->pipe; 395 struct st_query_object *stq = st_query_object(q); 396 struct st_buffer_object *stObj = st_buffer_object(buf); 397 boolean wait = pname == GL_QUERY_RESULT; 398 enum pipe_query_value_type result_type; 399 int index; 400 401 /* GL_QUERY_TARGET is a bit of an extension since it has nothing to 402 * do with the GPU end of the query. Write it in "by hand". 403 */ 404 if (pname == GL_QUERY_TARGET) { 405 /* Assume that the data must be LE. The endianness situation wrt CPU and 406 * GPU is incredibly confusing, but the vast majority of GPUs are 407 * LE. When a BE one comes along, this needs some form of resolution. 408 */ 409 unsigned data[2] = { CPU_TO_LE32(q->Target), 0 }; 410 pipe_buffer_write(pipe, stObj->buffer, offset, 411 (ptype == GL_INT64_ARB || 412 ptype == GL_UNSIGNED_INT64_ARB) ? 8 : 4, 413 data); 414 return; 415 } 416 417 switch (ptype) { 418 case GL_INT: 419 result_type = PIPE_QUERY_TYPE_I32; 420 break; 421 case GL_UNSIGNED_INT: 422 result_type = PIPE_QUERY_TYPE_U32; 423 break; 424 case GL_INT64_ARB: 425 result_type = PIPE_QUERY_TYPE_I64; 426 break; 427 case GL_UNSIGNED_INT64_ARB: 428 result_type = PIPE_QUERY_TYPE_U64; 429 break; 430 default: 431 unreachable("Unexpected result type"); 432 } 433 434 if (pname == GL_QUERY_RESULT_AVAILABLE) { 435 index = -1; 436 } else if (stq->type == PIPE_QUERY_PIPELINE_STATISTICS) { 437 switch (q->Target) { 438 case GL_VERTICES_SUBMITTED_ARB: 439 index = PIPE_STAT_QUERY_IA_VERTICES; 440 break; 441 case GL_PRIMITIVES_SUBMITTED_ARB: 442 index = PIPE_STAT_QUERY_IA_PRIMITIVES; 443 break; 444 case GL_VERTEX_SHADER_INVOCATIONS_ARB: 445 index = PIPE_STAT_QUERY_VS_INVOCATIONS; 446 break; 447 case GL_GEOMETRY_SHADER_INVOCATIONS: 448 index = PIPE_STAT_QUERY_GS_INVOCATIONS; 449 break; 450 case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB: 451 index = PIPE_STAT_QUERY_GS_PRIMITIVES; 452 break; 453 case GL_CLIPPING_INPUT_PRIMITIVES_ARB: 454 index = PIPE_STAT_QUERY_C_INVOCATIONS; 455 break; 456 case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB: 457 index = PIPE_STAT_QUERY_C_PRIMITIVES; 458 break; 459 case GL_FRAGMENT_SHADER_INVOCATIONS_ARB: 460 index = PIPE_STAT_QUERY_PS_INVOCATIONS; 461 break; 462 case GL_TESS_CONTROL_SHADER_PATCHES_ARB: 463 index = PIPE_STAT_QUERY_HS_INVOCATIONS; 464 break; 465 case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB: 466 index = PIPE_STAT_QUERY_DS_INVOCATIONS; 467 break; 468 case GL_COMPUTE_SHADER_INVOCATIONS_ARB: 469 index = PIPE_STAT_QUERY_CS_INVOCATIONS; 470 break; 471 default: 472 unreachable("Unexpected target"); 473 } 474 } else { 475 index = 0; 476 } 477 478 pipe->get_query_result_resource(pipe, stq->pq, wait, result_type, index, 479 stObj->buffer, offset); 480} 481 482void st_init_query_functions(struct dd_function_table *functions) 483{ 484 functions->NewQueryObject = st_NewQueryObject; 485 functions->DeleteQuery = st_DeleteQuery; 486 functions->BeginQuery = st_BeginQuery; 487 functions->EndQuery = st_EndQuery; 488 functions->WaitQuery = st_WaitQuery; 489 functions->CheckQuery = st_CheckQuery; 490 functions->GetTimestamp = st_GetTimestamp; 491 functions->StoreQueryResult = st_StoreQueryResult; 492} 493