swr_query.cpp revision 5815c8b3d3b7fe3311ac51533438f24f09768ad6
1/**************************************************************************** 2 * Copyright (C) 2015 Intel Corporation. All Rights Reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 ***************************************************************************/ 23 24#include "pipe/p_defines.h" 25#include "util/u_memory.h" 26#include "os/os_time.h" 27#include "swr_context.h" 28#include "swr_fence.h" 29#include "swr_query.h" 30#include "swr_screen.h" 31#include "swr_state.h" 32 33 34static struct swr_query * 35swr_query(struct pipe_query *p) 36{ 37 return (struct swr_query *)p; 38} 39 40static struct pipe_query * 41swr_create_query(struct pipe_context *pipe, unsigned type, unsigned index) 42{ 43 struct swr_query *pq; 44 45 assert(type < PIPE_QUERY_TYPES); 46 assert(index < MAX_SO_STREAMS); 47 48 pq = CALLOC_STRUCT(swr_query); 49 50 if (pq) { 51 pq->type = type; 52 pq->index = index; 53 } 54 55 return (struct pipe_query *)pq; 56} 57 58 59static void 60swr_destroy_query(struct pipe_context *pipe, struct pipe_query *q) 61{ 62 struct swr_query *pq = swr_query(q); 63 64 if (pq->fence) { 65 if (!swr_is_fence_pending(pq->fence)) { 66 swr_fence_submit(swr_context(pipe), pq->fence); 67 swr_fence_finish(pipe->screen, pq->fence, 0); 68 } 69 swr_fence_reference(pipe->screen, &pq->fence, NULL); 70 } 71 72 FREE(pq); 73} 74 75 76// XXX Create a fence callback, rather than stalling SwrWaitForIdle 77static void 78swr_gather_stats(struct pipe_context *pipe, struct swr_query *pq) 79{ 80 struct swr_context *ctx = swr_context(pipe); 81 82 assert(pq->result); 83 union pipe_query_result *result = pq->result; 84 boolean enable_stats = pq->enable_stats; 85 SWR_STATS swr_stats = {0}; 86 87 if (pq->fence) { 88 if (!swr_is_fence_pending(pq->fence)) { 89 swr_fence_submit(ctx, pq->fence); 90 swr_fence_finish(pipe->screen, pq->fence, 0); 91 } 92 swr_fence_reference(pipe->screen, &pq->fence, NULL); 93 } 94 95 /* 96 * These queries don't need SWR Stats enabled in the core 97 * Set and return. 98 */ 99 switch (pq->type) { 100 case PIPE_QUERY_TIMESTAMP: 101 case PIPE_QUERY_TIME_ELAPSED: 102 result->u64 = swr_get_timestamp(pipe->screen); 103 return; 104 break; 105 case PIPE_QUERY_TIMESTAMP_DISJOINT: 106 /* nothing to do here */ 107 return; 108 break; 109 case PIPE_QUERY_GPU_FINISHED: 110 result->b = TRUE; /* XXX TODO Add an api func to SWR to compare drawId 111 vs LastRetiredId? */ 112 return; 113 break; 114 default: 115 /* Any query that needs SwrCore stats */ 116 break; 117 } 118 119 /* 120 * All other results are collected from SwrCore counters 121 */ 122 123 /* XXX, Should turn this into a fence callback and skip the stall */ 124 SwrGetStats(ctx->swrContext, &swr_stats); 125 /* SwrGetStats returns immediately, wait for collection */ 126 SwrWaitForIdle(ctx->swrContext); 127 128 switch (pq->type) { 129 case PIPE_QUERY_OCCLUSION_PREDICATE: 130 case PIPE_QUERY_OCCLUSION_COUNTER: 131 result->u64 = swr_stats.DepthPassCount; 132 break; 133 case PIPE_QUERY_PRIMITIVES_GENERATED: 134 result->u64 = swr_stats.IaPrimitives; 135 break; 136 case PIPE_QUERY_PRIMITIVES_EMITTED: 137 result->u64 = swr_stats.SoNumPrimsWritten[pq->index]; 138 break; 139 case PIPE_QUERY_SO_STATISTICS: 140 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: { 141 struct pipe_query_data_so_statistics *so_stats = &result->so_statistics; 142 so_stats->num_primitives_written = 143 swr_stats.SoNumPrimsWritten[pq->index]; 144 so_stats->primitives_storage_needed = 145 swr_stats.SoPrimStorageNeeded[pq->index]; 146 } break; 147 case PIPE_QUERY_PIPELINE_STATISTICS: { 148 struct pipe_query_data_pipeline_statistics *p_stats = 149 &result->pipeline_statistics; 150 p_stats->ia_vertices = swr_stats.IaVertices; 151 p_stats->ia_primitives = swr_stats.IaPrimitives; 152 p_stats->vs_invocations = swr_stats.VsInvocations; 153 p_stats->gs_invocations = swr_stats.GsInvocations; 154 p_stats->gs_primitives = swr_stats.GsPrimitives; 155 p_stats->c_invocations = swr_stats.CPrimitives; 156 p_stats->c_primitives = swr_stats.CPrimitives; 157 p_stats->ps_invocations = swr_stats.PsInvocations; 158 p_stats->hs_invocations = swr_stats.HsInvocations; 159 p_stats->ds_invocations = swr_stats.DsInvocations; 160 p_stats->cs_invocations = swr_stats.CsInvocations; 161 } break; 162 default: 163 assert(0 && "Unsupported query"); 164 break; 165 } 166 167 /* Only change stat collection if there are no active queries */ 168 if (ctx->active_queries == 0) 169 SwrEnableStats(ctx->swrContext, enable_stats); 170} 171 172 173static boolean 174swr_get_query_result(struct pipe_context *pipe, 175 struct pipe_query *q, 176 boolean wait, 177 union pipe_query_result *result) 178{ 179 struct swr_context *ctx = swr_context(pipe); 180 struct swr_query *pq = swr_query(q); 181 182 if (pq->fence) { 183 if (!swr_is_fence_pending(pq->fence)) { 184 swr_fence_submit(ctx, pq->fence); 185 if (!wait) 186 return FALSE; 187 swr_fence_finish(pipe->screen, pq->fence, 0); 188 } 189 swr_fence_reference(pipe->screen, &pq->fence, NULL); 190 } 191 192 /* XXX: Need to handle counter rollover */ 193 194 switch (pq->type) { 195 /* Booleans */ 196 case PIPE_QUERY_OCCLUSION_PREDICATE: 197 result->b = pq->end.u64 != pq->start.u64 ? TRUE : FALSE; 198 break; 199 case PIPE_QUERY_GPU_FINISHED: 200 result->b = pq->end.b; 201 break; 202 /* Counters */ 203 case PIPE_QUERY_OCCLUSION_COUNTER: 204 case PIPE_QUERY_TIMESTAMP: 205 case PIPE_QUERY_TIME_ELAPSED: 206 case PIPE_QUERY_PRIMITIVES_GENERATED: 207 case PIPE_QUERY_PRIMITIVES_EMITTED: 208 result->u64 = pq->end.u64 - pq->start.u64; 209 break; 210 /* Structures */ 211 case PIPE_QUERY_SO_STATISTICS: { 212 struct pipe_query_data_so_statistics *so_stats = &result->so_statistics; 213 struct pipe_query_data_so_statistics *start = &pq->start.so_statistics; 214 struct pipe_query_data_so_statistics *end = &pq->end.so_statistics; 215 so_stats->num_primitives_written = 216 end->num_primitives_written - start->num_primitives_written; 217 so_stats->primitives_storage_needed = 218 end->primitives_storage_needed - start->primitives_storage_needed; 219 } break; 220 case PIPE_QUERY_TIMESTAMP_DISJOINT: { 221 /* os_get_time_nano returns nanoseconds */ 222 result->timestamp_disjoint.frequency = UINT64_C(1000000000); 223 result->timestamp_disjoint.disjoint = FALSE; 224 } break; 225 case PIPE_QUERY_PIPELINE_STATISTICS: { 226 struct pipe_query_data_pipeline_statistics *p_stats = 227 &result->pipeline_statistics; 228 struct pipe_query_data_pipeline_statistics *start = 229 &pq->start.pipeline_statistics; 230 struct pipe_query_data_pipeline_statistics *end = 231 &pq->end.pipeline_statistics; 232 p_stats->ia_vertices = end->ia_vertices - start->ia_vertices; 233 p_stats->ia_primitives = end->ia_primitives - start->ia_primitives; 234 p_stats->vs_invocations = end->vs_invocations - start->vs_invocations; 235 p_stats->gs_invocations = end->gs_invocations - start->gs_invocations; 236 p_stats->gs_primitives = end->gs_primitives - start->gs_primitives; 237 p_stats->c_invocations = end->c_invocations - start->c_invocations; 238 p_stats->c_primitives = end->c_primitives - start->c_primitives; 239 p_stats->ps_invocations = end->ps_invocations - start->ps_invocations; 240 p_stats->hs_invocations = end->hs_invocations - start->hs_invocations; 241 p_stats->ds_invocations = end->ds_invocations - start->ds_invocations; 242 p_stats->cs_invocations = end->cs_invocations - start->cs_invocations; 243 } break; 244 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: { 245 struct pipe_query_data_so_statistics *start = &pq->start.so_statistics; 246 struct pipe_query_data_so_statistics *end = &pq->end.so_statistics; 247 uint64_t num_primitives_written = 248 end->num_primitives_written - start->num_primitives_written; 249 uint64_t primitives_storage_needed = 250 end->primitives_storage_needed - start->primitives_storage_needed; 251 result->b = num_primitives_written > primitives_storage_needed; 252 } break; 253 default: 254 assert(0 && "Unsupported query"); 255 break; 256 } 257 258 return TRUE; 259} 260 261static boolean 262swr_begin_query(struct pipe_context *pipe, struct pipe_query *q) 263{ 264 struct swr_context *ctx = swr_context(pipe); 265 struct swr_query *pq = swr_query(q); 266 267 /* Initialize Results */ 268 memset(&pq->start, 0, sizeof(pq->start)); 269 memset(&pq->end, 0, sizeof(pq->end)); 270 271 /* Gather start stats and enable SwrCore counters */ 272 pq->result = &pq->start; 273 pq->enable_stats = TRUE; 274 swr_gather_stats(pipe, pq); 275 ctx->active_queries++; 276 277 /* override start timestamp to 0 for TIMESTAMP query */ 278 if (pq->type == PIPE_QUERY_TIMESTAMP) 279 pq->start.u64 = 0; 280 281 return true; 282} 283 284static bool 285swr_end_query(struct pipe_context *pipe, struct pipe_query *q) 286{ 287 struct swr_context *ctx = swr_context(pipe); 288 struct swr_query *pq = swr_query(q); 289 290 assert(ctx->active_queries 291 && "swr_end_query, there are no active queries!"); 292 ctx->active_queries--; 293 294 /* Gather end stats and disable SwrCore counters */ 295 pq->result = &pq->end; 296 pq->enable_stats = FALSE; 297 swr_gather_stats(pipe, pq); 298 return true; 299} 300 301 302boolean 303swr_check_render_cond(struct pipe_context *pipe) 304{ 305 struct swr_context *ctx = swr_context(pipe); 306 boolean b, wait; 307 uint64_t result; 308 309 if (!ctx->render_cond_query) 310 return TRUE; /* no query predicate, draw normally */ 311 312 wait = (ctx->render_cond_mode == PIPE_RENDER_COND_WAIT 313 || ctx->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT); 314 315 b = pipe->get_query_result( 316 pipe, ctx->render_cond_query, wait, (union pipe_query_result *)&result); 317 if (b) 318 return ((!result) == ctx->render_cond_cond); 319 else 320 return TRUE; 321} 322 323 324static void 325swr_set_active_query_state(struct pipe_context *pipe, boolean enable) 326{ 327} 328 329void 330swr_query_init(struct pipe_context *pipe) 331{ 332 struct swr_context *ctx = swr_context(pipe); 333 334 pipe->create_query = swr_create_query; 335 pipe->destroy_query = swr_destroy_query; 336 pipe->begin_query = swr_begin_query; 337 pipe->end_query = swr_end_query; 338 pipe->get_query_result = swr_get_query_result; 339 pipe->set_active_query_state = swr_set_active_query_state; 340 341 ctx->active_queries = 0; 342} 343