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 "main/imports.h" 37 #include "main/compiler.h" 38 #include "main/context.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 49 50 static struct gl_query_object * 51 st_NewQueryObject(struct gl_context *ctx, GLuint id) 52 { 53 struct st_query_object *stq = ST_CALLOC_STRUCT(st_query_object); 54 if (stq) { 55 stq->base.Id = id; 56 stq->base.Ready = GL_TRUE; 57 stq->pq = NULL; 58 stq->type = PIPE_QUERY_TYPES; /* an invalid value */ 59 return &stq->base; 60 } 61 return NULL; 62 } 63 64 65 static void 66 free_queries(struct pipe_context *pipe, struct st_query_object *stq) 67 { 68 if (stq->pq) { 69 pipe->destroy_query(pipe, stq->pq); 70 stq->pq = NULL; 71 } 72 73 if (stq->pq_begin) { 74 pipe->destroy_query(pipe, stq->pq_begin); 75 stq->pq_begin = NULL; 76 } 77 } 78 79 80 static void 81 st_DeleteQuery(struct gl_context *ctx, struct gl_query_object *q) 82 { 83 struct pipe_context *pipe = st_context(ctx)->pipe; 84 struct st_query_object *stq = st_query_object(q); 85 86 free_queries(pipe, stq); 87 88 free(stq); 89 } 90 91 92 static void 93 st_BeginQuery(struct gl_context *ctx, struct gl_query_object *q) 94 { 95 struct st_context *st = st_context(ctx); 96 struct pipe_context *pipe = st->pipe; 97 struct st_query_object *stq = st_query_object(q); 98 unsigned type; 99 bool ret = false; 100 101 st_flush_bitmap_cache(st_context(ctx)); 102 103 /* convert GL query type to Gallium query type */ 104 switch (q->Target) { 105 case GL_ANY_SAMPLES_PASSED: 106 type = PIPE_QUERY_OCCLUSION_PREDICATE; 107 break; 108 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: 109 type = PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE; 110 break; 111 case GL_SAMPLES_PASSED_ARB: 112 type = PIPE_QUERY_OCCLUSION_COUNTER; 113 break; 114 case GL_PRIMITIVES_GENERATED: 115 type = PIPE_QUERY_PRIMITIVES_GENERATED; 116 break; 117 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 118 type = PIPE_QUERY_PRIMITIVES_EMITTED; 119 break; 120 case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB: 121 type = PIPE_QUERY_SO_OVERFLOW_PREDICATE; 122 break; 123 case GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB: 124 type = PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE; 125 break; 126 case GL_TIME_ELAPSED: 127 if (st->has_time_elapsed) 128 type = PIPE_QUERY_TIME_ELAPSED; 129 else 130 type = PIPE_QUERY_TIMESTAMP; 131 break; 132 case GL_VERTICES_SUBMITTED_ARB: 133 case GL_PRIMITIVES_SUBMITTED_ARB: 134 case GL_VERTEX_SHADER_INVOCATIONS_ARB: 135 case GL_TESS_CONTROL_SHADER_PATCHES_ARB: 136 case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB: 137 case GL_GEOMETRY_SHADER_INVOCATIONS: 138 case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB: 139 case GL_FRAGMENT_SHADER_INVOCATIONS_ARB: 140 case GL_COMPUTE_SHADER_INVOCATIONS_ARB: 141 case GL_CLIPPING_INPUT_PRIMITIVES_ARB: 142 case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB: 143 type = PIPE_QUERY_PIPELINE_STATISTICS; 144 break; 145 default: 146 assert(0 && "unexpected query target in st_BeginQuery()"); 147 return; 148 } 149 150 if (stq->type != type) { 151 /* free old query of different type */ 152 free_queries(pipe, stq); 153 stq->type = PIPE_QUERY_TYPES; /* an invalid value */ 154 } 155 156 if (q->Target == GL_TIME_ELAPSED && 157 type == PIPE_QUERY_TIMESTAMP) { 158 /* Determine time elapsed by emitting two timestamp queries. */ 159 if (!stq->pq_begin) { 160 stq->pq_begin = pipe->create_query(pipe, type, 0); 161 stq->type = type; 162 } 163 if (stq->pq_begin) 164 ret = pipe->end_query(pipe, stq->pq_begin); 165 } else { 166 if (!stq->pq) { 167 stq->pq = pipe->create_query(pipe, type, q->Stream); 168 stq->type = type; 169 } 170 if (stq->pq) 171 ret = pipe->begin_query(pipe, stq->pq); 172 } 173 174 if (!ret) { 175 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery"); 176 177 free_queries(pipe, stq); 178 q->Active = GL_FALSE; 179 return; 180 } 181 182 assert(stq->type == type); 183 } 184 185 186 static void 187 st_EndQuery(struct gl_context *ctx, struct gl_query_object *q) 188 { 189 struct pipe_context *pipe = st_context(ctx)->pipe; 190 struct st_query_object *stq = st_query_object(q); 191 bool ret = false; 192 193 st_flush_bitmap_cache(st_context(ctx)); 194 195 if ((q->Target == GL_TIMESTAMP || 196 q->Target == GL_TIME_ELAPSED) && 197 !stq->pq) { 198 stq->pq = pipe->create_query(pipe, PIPE_QUERY_TIMESTAMP, 0); 199 stq->type = PIPE_QUERY_TIMESTAMP; 200 } 201 202 if (stq->pq) 203 ret = pipe->end_query(pipe, stq->pq); 204 205 if (!ret) { 206 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glEndQuery"); 207 return; 208 } 209 } 210 211 212 static boolean 213 get_query_result(struct pipe_context *pipe, 214 struct st_query_object *stq, 215 boolean wait) 216 { 217 union pipe_query_result data; 218 219 if (!stq->pq) { 220 /* Only needed in case we failed to allocate the gallium query earlier. 221 * Return TRUE so we don't spin on this forever. 222 */ 223 return TRUE; 224 } 225 226 if (!pipe->get_query_result(pipe, stq->pq, wait, &data)) 227 return FALSE; 228 229 switch (stq->base.Target) { 230 case GL_VERTICES_SUBMITTED_ARB: 231 stq->base.Result = data.pipeline_statistics.ia_vertices; 232 break; 233 case GL_PRIMITIVES_SUBMITTED_ARB: 234 stq->base.Result = data.pipeline_statistics.ia_primitives; 235 break; 236 case GL_VERTEX_SHADER_INVOCATIONS_ARB: 237 stq->base.Result = data.pipeline_statistics.vs_invocations; 238 break; 239 case GL_TESS_CONTROL_SHADER_PATCHES_ARB: 240 stq->base.Result = data.pipeline_statistics.hs_invocations; 241 break; 242 case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB: 243 stq->base.Result = data.pipeline_statistics.ds_invocations; 244 break; 245 case GL_GEOMETRY_SHADER_INVOCATIONS: 246 stq->base.Result = data.pipeline_statistics.gs_invocations; 247 break; 248 case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB: 249 stq->base.Result = data.pipeline_statistics.gs_primitives; 250 break; 251 case GL_FRAGMENT_SHADER_INVOCATIONS_ARB: 252 stq->base.Result = data.pipeline_statistics.ps_invocations; 253 break; 254 case GL_COMPUTE_SHADER_INVOCATIONS_ARB: 255 stq->base.Result = data.pipeline_statistics.cs_invocations; 256 break; 257 case GL_CLIPPING_INPUT_PRIMITIVES_ARB: 258 stq->base.Result = data.pipeline_statistics.c_invocations; 259 break; 260 case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB: 261 stq->base.Result = data.pipeline_statistics.c_primitives; 262 break; 263 default: 264 switch (stq->type) { 265 case PIPE_QUERY_OCCLUSION_PREDICATE: 266 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 267 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: 268 case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE: 269 stq->base.Result = !!data.b; 270 break; 271 default: 272 stq->base.Result = data.u64; 273 break; 274 } 275 break; 276 } 277 278 if (stq->base.Target == GL_TIME_ELAPSED && 279 stq->type == PIPE_QUERY_TIMESTAMP) { 280 /* Calculate the elapsed time from the two timestamp queries */ 281 GLuint64EXT Result0 = 0; 282 assert(stq->pq_begin); 283 pipe->get_query_result(pipe, stq->pq_begin, TRUE, (void *)&Result0); 284 stq->base.Result -= Result0; 285 } else { 286 assert(!stq->pq_begin); 287 } 288 289 return TRUE; 290 } 291 292 293 static void 294 st_WaitQuery(struct gl_context *ctx, struct gl_query_object *q) 295 { 296 struct pipe_context *pipe = st_context(ctx)->pipe; 297 struct st_query_object *stq = st_query_object(q); 298 299 /* this function should only be called if we don't have a ready result */ 300 assert(!stq->base.Ready); 301 302 while (!stq->base.Ready && 303 !get_query_result(pipe, stq, TRUE)) 304 { 305 /* nothing */ 306 } 307 308 q->Ready = GL_TRUE; 309 } 310 311 312 static void 313 st_CheckQuery(struct gl_context *ctx, struct gl_query_object *q) 314 { 315 struct pipe_context *pipe = st_context(ctx)->pipe; 316 struct st_query_object *stq = st_query_object(q); 317 assert(!q->Ready); /* we should not get called if Ready is TRUE */ 318 q->Ready = get_query_result(pipe, stq, FALSE); 319 } 320 321 322 static uint64_t 323 st_GetTimestamp(struct gl_context *ctx) 324 { 325 struct pipe_context *pipe = st_context(ctx)->pipe; 326 struct pipe_screen *screen = pipe->screen; 327 328 /* Prefer the per-screen function */ 329 if (screen->get_timestamp) { 330 return screen->get_timestamp(screen); 331 } 332 else { 333 /* Fall back to the per-context function */ 334 assert(pipe->get_timestamp); 335 return pipe->get_timestamp(pipe); 336 } 337 } 338 339 static void 340 st_StoreQueryResult(struct gl_context *ctx, struct gl_query_object *q, 341 struct gl_buffer_object *buf, intptr_t offset, 342 GLenum pname, GLenum ptype) 343 { 344 struct pipe_context *pipe = st_context(ctx)->pipe; 345 struct st_query_object *stq = st_query_object(q); 346 struct st_buffer_object *stObj = st_buffer_object(buf); 347 boolean wait = pname == GL_QUERY_RESULT; 348 enum pipe_query_value_type result_type; 349 int index; 350 351 /* GL_QUERY_TARGET is a bit of an extension since it has nothing to 352 * do with the GPU end of the query. Write it in "by hand". 353 */ 354 if (pname == GL_QUERY_TARGET) { 355 /* Assume that the data must be LE. The endianness situation wrt CPU and 356 * GPU is incredibly confusing, but the vast majority of GPUs are 357 * LE. When a BE one comes along, this needs some form of resolution. 358 */ 359 unsigned data[2] = { CPU_TO_LE32(q->Target), 0 }; 360 pipe_buffer_write(pipe, stObj->buffer, offset, 361 (ptype == GL_INT64_ARB || 362 ptype == GL_UNSIGNED_INT64_ARB) ? 8 : 4, 363 data); 364 return; 365 } 366 367 switch (ptype) { 368 case GL_INT: 369 result_type = PIPE_QUERY_TYPE_I32; 370 break; 371 case GL_UNSIGNED_INT: 372 result_type = PIPE_QUERY_TYPE_U32; 373 break; 374 case GL_INT64_ARB: 375 result_type = PIPE_QUERY_TYPE_I64; 376 break; 377 case GL_UNSIGNED_INT64_ARB: 378 result_type = PIPE_QUERY_TYPE_U64; 379 break; 380 default: 381 unreachable("Unexpected result type"); 382 } 383 384 if (pname == GL_QUERY_RESULT_AVAILABLE) { 385 index = -1; 386 } else if (stq->type == PIPE_QUERY_PIPELINE_STATISTICS) { 387 switch (q->Target) { 388 case GL_VERTICES_SUBMITTED_ARB: 389 index = 0; 390 break; 391 case GL_PRIMITIVES_SUBMITTED_ARB: 392 index = 1; 393 break; 394 case GL_VERTEX_SHADER_INVOCATIONS_ARB: 395 index = 2; 396 break; 397 case GL_GEOMETRY_SHADER_INVOCATIONS: 398 index = 3; 399 break; 400 case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB: 401 index = 4; 402 break; 403 case GL_CLIPPING_INPUT_PRIMITIVES_ARB: 404 index = 5; 405 break; 406 case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB: 407 index = 6; 408 break; 409 case GL_FRAGMENT_SHADER_INVOCATIONS_ARB: 410 index = 7; 411 break; 412 case GL_TESS_CONTROL_SHADER_PATCHES_ARB: 413 index = 8; 414 break; 415 case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB: 416 index = 9; 417 break; 418 case GL_COMPUTE_SHADER_INVOCATIONS_ARB: 419 index = 10; 420 break; 421 default: 422 unreachable("Unexpected target"); 423 } 424 } else { 425 index = 0; 426 } 427 428 pipe->get_query_result_resource(pipe, stq->pq, wait, result_type, index, 429 stObj->buffer, offset); 430 } 431 432 void st_init_query_functions(struct dd_function_table *functions) 433 { 434 functions->NewQueryObject = st_NewQueryObject; 435 functions->DeleteQuery = st_DeleteQuery; 436 functions->BeginQuery = st_BeginQuery; 437 functions->EndQuery = st_EndQuery; 438 functions->WaitQuery = st_WaitQuery; 439 functions->CheckQuery = st_CheckQuery; 440 functions->GetTimestamp = st_GetTimestamp; 441 functions->StoreQueryResult = st_StoreQueryResult; 442 } 443