lp_query.c revision 848b8605
1/************************************************************************** 2 * 3 * Copyright 2007 VMware, Inc. 4 * Copyright 2010 VMware, Inc. 5 * All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, sub license, and/or sell copies of the Software, and to 12 * permit persons to whom the Software is furnished to do so, subject to 13 * the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the 16 * next paragraph) shall be included in all copies or substantial portions 17 * of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 22 * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR 23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 **************************************************************************/ 28 29/* Authors: 30 * Keith Whitwell, Qicheng Christopher Li, Brian Paul 31 */ 32 33#include "draw/draw_context.h" 34#include "pipe/p_defines.h" 35#include "util/u_memory.h" 36#include "os/os_time.h" 37#include "lp_context.h" 38#include "lp_flush.h" 39#include "lp_fence.h" 40#include "lp_query.h" 41#include "lp_screen.h" 42#include "lp_state.h" 43#include "lp_rast.h" 44 45 46static struct llvmpipe_query *llvmpipe_query( struct pipe_query *p ) 47{ 48 return (struct llvmpipe_query *)p; 49} 50 51static struct pipe_query * 52llvmpipe_create_query(struct pipe_context *pipe, 53 unsigned type, 54 unsigned index) 55{ 56 struct llvmpipe_query *pq; 57 58 assert(type < PIPE_QUERY_TYPES); 59 60 pq = CALLOC_STRUCT( llvmpipe_query ); 61 62 if (pq) { 63 pq->type = type; 64 } 65 66 return (struct pipe_query *) pq; 67} 68 69 70static void 71llvmpipe_destroy_query(struct pipe_context *pipe, struct pipe_query *q) 72{ 73 struct llvmpipe_query *pq = llvmpipe_query(q); 74 75 /* Ideally we would refcount queries & not get destroyed until the 76 * last scene had finished with us. 77 */ 78 if (pq->fence) { 79 if (!lp_fence_issued(pq->fence)) 80 llvmpipe_flush(pipe, NULL, __FUNCTION__); 81 82 if (!lp_fence_signalled(pq->fence)) 83 lp_fence_wait(pq->fence); 84 85 lp_fence_reference(&pq->fence, NULL); 86 } 87 88 FREE(pq); 89} 90 91 92static boolean 93llvmpipe_get_query_result(struct pipe_context *pipe, 94 struct pipe_query *q, 95 boolean wait, 96 union pipe_query_result *vresult) 97{ 98 struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen); 99 unsigned num_threads = MAX2(1, screen->num_threads); 100 struct llvmpipe_query *pq = llvmpipe_query(q); 101 uint64_t *result = (uint64_t *)vresult; 102 int i; 103 104 if (pq->fence) { 105 /* only have a fence if there was a scene */ 106 if (!lp_fence_signalled(pq->fence)) { 107 if (!lp_fence_issued(pq->fence)) 108 llvmpipe_flush(pipe, NULL, __FUNCTION__); 109 110 if (!wait) 111 return FALSE; 112 113 lp_fence_wait(pq->fence); 114 } 115 } 116 117 /* Sum the results from each of the threads: 118 */ 119 *result = 0; 120 121 switch (pq->type) { 122 case PIPE_QUERY_OCCLUSION_COUNTER: 123 for (i = 0; i < num_threads; i++) { 124 *result += pq->end[i]; 125 } 126 break; 127 case PIPE_QUERY_OCCLUSION_PREDICATE: 128 for (i = 0; i < num_threads; i++) { 129 /* safer (still not guaranteed) when there's an overflow */ 130 vresult->b = vresult->b || pq->end[i]; 131 } 132 break; 133 case PIPE_QUERY_TIMESTAMP: 134 for (i = 0; i < num_threads; i++) { 135 if (pq->end[i] > *result) { 136 *result = pq->end[i]; 137 } 138 } 139 break; 140 case PIPE_QUERY_TIMESTAMP_DISJOINT: { 141 struct pipe_query_data_timestamp_disjoint *td = 142 (struct pipe_query_data_timestamp_disjoint *)vresult; 143 /* os_get_time_nano return nanoseconds */ 144 td->frequency = UINT64_C(1000000000); 145 td->disjoint = FALSE; 146 } 147 break; 148 case PIPE_QUERY_GPU_FINISHED: 149 vresult->b = TRUE; 150 break; 151 case PIPE_QUERY_PRIMITIVES_GENERATED: 152 *result = pq->num_primitives_generated; 153 break; 154 case PIPE_QUERY_PRIMITIVES_EMITTED: 155 *result = pq->num_primitives_written; 156 break; 157 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: 158 vresult->b = pq->num_primitives_generated > pq->num_primitives_written; 159 break; 160 case PIPE_QUERY_SO_STATISTICS: { 161 struct pipe_query_data_so_statistics *stats = 162 (struct pipe_query_data_so_statistics *)vresult; 163 stats->num_primitives_written = pq->num_primitives_written; 164 stats->primitives_storage_needed = pq->num_primitives_generated; 165 } 166 break; 167 case PIPE_QUERY_PIPELINE_STATISTICS: { 168 struct pipe_query_data_pipeline_statistics *stats = 169 (struct pipe_query_data_pipeline_statistics *)vresult; 170 /* only ps_invocations come from binned query */ 171 for (i = 0; i < num_threads; i++) { 172 pq->stats.ps_invocations += pq->end[i]; 173 } 174 pq->stats.ps_invocations *= LP_RASTER_BLOCK_SIZE * LP_RASTER_BLOCK_SIZE; 175 *stats = pq->stats; 176 } 177 break; 178 default: 179 assert(0); 180 break; 181 } 182 183 return TRUE; 184} 185 186 187static void 188llvmpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q) 189{ 190 struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe ); 191 struct llvmpipe_query *pq = llvmpipe_query(q); 192 193 /* Check if the query is already in the scene. If so, we need to 194 * flush the scene now. Real apps shouldn't re-use a query in a 195 * frame of rendering. 196 */ 197 if (pq->fence && !lp_fence_issued(pq->fence)) { 198 llvmpipe_finish(pipe, __FUNCTION__); 199 } 200 201 202 memset(pq->start, 0, sizeof(pq->start)); 203 memset(pq->end, 0, sizeof(pq->end)); 204 lp_setup_begin_query(llvmpipe->setup, pq); 205 206 switch (pq->type) { 207 case PIPE_QUERY_PRIMITIVES_EMITTED: 208 pq->num_primitives_written = llvmpipe->so_stats.num_primitives_written; 209 break; 210 case PIPE_QUERY_PRIMITIVES_GENERATED: 211 pq->num_primitives_generated = llvmpipe->so_stats.primitives_storage_needed; 212 break; 213 case PIPE_QUERY_SO_STATISTICS: 214 pq->num_primitives_written = llvmpipe->so_stats.num_primitives_written; 215 pq->num_primitives_generated = llvmpipe->so_stats.primitives_storage_needed; 216 break; 217 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: 218 pq->num_primitives_written = llvmpipe->so_stats.num_primitives_written; 219 pq->num_primitives_generated = llvmpipe->so_stats.primitives_storage_needed; 220 break; 221 case PIPE_QUERY_PIPELINE_STATISTICS: 222 /* reset our cache */ 223 if (llvmpipe->active_statistics_queries == 0) { 224 memset(&llvmpipe->pipeline_statistics, 0, 225 sizeof(llvmpipe->pipeline_statistics)); 226 } 227 memcpy(&pq->stats, &llvmpipe->pipeline_statistics, sizeof(pq->stats)); 228 llvmpipe->active_statistics_queries++; 229 break; 230 case PIPE_QUERY_OCCLUSION_COUNTER: 231 case PIPE_QUERY_OCCLUSION_PREDICATE: 232 llvmpipe->active_occlusion_queries++; 233 llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY; 234 break; 235 default: 236 break; 237 } 238} 239 240 241static void 242llvmpipe_end_query(struct pipe_context *pipe, struct pipe_query *q) 243{ 244 struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe ); 245 struct llvmpipe_query *pq = llvmpipe_query(q); 246 247 lp_setup_end_query(llvmpipe->setup, pq); 248 249 switch (pq->type) { 250 251 case PIPE_QUERY_PRIMITIVES_EMITTED: 252 pq->num_primitives_written = 253 llvmpipe->so_stats.num_primitives_written - pq->num_primitives_written; 254 break; 255 case PIPE_QUERY_PRIMITIVES_GENERATED: 256 pq->num_primitives_generated = 257 llvmpipe->so_stats.primitives_storage_needed - pq->num_primitives_generated; 258 break; 259 case PIPE_QUERY_SO_STATISTICS: 260 pq->num_primitives_written = 261 llvmpipe->so_stats.num_primitives_written - pq->num_primitives_written; 262 pq->num_primitives_generated = 263 llvmpipe->so_stats.primitives_storage_needed - pq->num_primitives_generated; 264 break; 265 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: 266 pq->num_primitives_written = 267 llvmpipe->so_stats.num_primitives_written - pq->num_primitives_written; 268 pq->num_primitives_generated = 269 llvmpipe->so_stats.primitives_storage_needed - pq->num_primitives_generated; 270 break; 271 case PIPE_QUERY_PIPELINE_STATISTICS: 272 pq->stats.ia_vertices = 273 llvmpipe->pipeline_statistics.ia_vertices - pq->stats.ia_vertices; 274 pq->stats.ia_primitives = 275 llvmpipe->pipeline_statistics.ia_primitives - pq->stats.ia_primitives; 276 pq->stats.vs_invocations = 277 llvmpipe->pipeline_statistics.vs_invocations - pq->stats.vs_invocations; 278 pq->stats.gs_invocations = 279 llvmpipe->pipeline_statistics.gs_invocations - pq->stats.gs_invocations; 280 pq->stats.gs_primitives = 281 llvmpipe->pipeline_statistics.gs_primitives - pq->stats.gs_primitives; 282 pq->stats.c_invocations = 283 llvmpipe->pipeline_statistics.c_invocations - pq->stats.c_invocations; 284 pq->stats.c_primitives = 285 llvmpipe->pipeline_statistics.c_primitives - pq->stats.c_primitives; 286 pq->stats.ps_invocations = 287 llvmpipe->pipeline_statistics.ps_invocations - pq->stats.ps_invocations; 288 289 llvmpipe->active_statistics_queries--; 290 break; 291 case PIPE_QUERY_OCCLUSION_COUNTER: 292 case PIPE_QUERY_OCCLUSION_PREDICATE: 293 assert(llvmpipe->active_occlusion_queries); 294 llvmpipe->active_occlusion_queries--; 295 llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY; 296 break; 297 default: 298 break; 299 } 300} 301 302boolean 303llvmpipe_check_render_cond(struct llvmpipe_context *lp) 304{ 305 struct pipe_context *pipe = &lp->pipe; 306 boolean b, wait; 307 uint64_t result; 308 309 if (!lp->render_cond_query) 310 return TRUE; /* no query predicate, draw normally */ 311 312 wait = (lp->render_cond_mode == PIPE_RENDER_COND_WAIT || 313 lp->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT); 314 315 b = pipe->get_query_result(pipe, lp->render_cond_query, wait, (void*)&result); 316 if (b) 317 return (!result == lp->render_cond_cond); 318 else 319 return TRUE; 320} 321 322void llvmpipe_init_query_funcs(struct llvmpipe_context *llvmpipe ) 323{ 324 llvmpipe->pipe.create_query = llvmpipe_create_query; 325 llvmpipe->pipe.destroy_query = llvmpipe_destroy_query; 326 llvmpipe->pipe.begin_query = llvmpipe_begin_query; 327 llvmpipe->pipe.end_query = llvmpipe_end_query; 328 llvmpipe->pipe.get_query_result = llvmpipe_get_query_result; 329} 330 331 332