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 "util/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#include "common/os.h" 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 = (struct swr_query *) AlignedMalloc(sizeof(struct swr_query), 64); 49 memset(pq, 0, sizeof(*pq)); 50 51 if (pq) { 52 pq->type = type; 53 pq->index = index; 54 } 55 56 return (struct pipe_query *)pq; 57} 58 59 60static void 61swr_destroy_query(struct pipe_context *pipe, struct pipe_query *q) 62{ 63 struct swr_query *pq = swr_query(q); 64 65 if (pq->fence) { 66 if (swr_is_fence_pending(pq->fence)) 67 swr_fence_finish(pipe->screen, NULL, pq->fence, 0); 68 swr_fence_reference(pipe->screen, &pq->fence, NULL); 69 } 70 71 AlignedFree(pq); 72} 73 74 75static boolean 76swr_get_query_result(struct pipe_context *pipe, 77 struct pipe_query *q, 78 boolean wait, 79 union pipe_query_result *result) 80{ 81 struct swr_query *pq = swr_query(q); 82 unsigned index = pq->index; 83 84 if (pq->fence) { 85 if (!wait && !swr_is_fence_done(pq->fence)) 86 return FALSE; 87 88 swr_fence_finish(pipe->screen, NULL, pq->fence, 0); 89 swr_fence_reference(pipe->screen, &pq->fence, NULL); 90 } 91 92 /* All values are reset to 0 at swr_begin_query, except starting timestamp. 93 * Counters become simply end values. */ 94 switch (pq->type) { 95 /* Booleans */ 96 case PIPE_QUERY_OCCLUSION_PREDICATE: 97 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 98 result->b = pq->result.core.DepthPassCount != 0; 99 break; 100 case PIPE_QUERY_GPU_FINISHED: 101 result->b = TRUE; 102 break; 103 /* Counters */ 104 case PIPE_QUERY_OCCLUSION_COUNTER: 105 result->u64 = pq->result.core.DepthPassCount; 106 break; 107 case PIPE_QUERY_TIMESTAMP: 108 case PIPE_QUERY_TIME_ELAPSED: 109 result->u64 = pq->result.timestamp_end - pq->result.timestamp_start; 110 break; 111 case PIPE_QUERY_PRIMITIVES_GENERATED: 112 result->u64 = pq->result.coreFE.IaPrimitives; 113 break; 114 case PIPE_QUERY_PRIMITIVES_EMITTED: 115 result->u64 = pq->result.coreFE.SoNumPrimsWritten[index]; 116 break; 117 /* Structures */ 118 case PIPE_QUERY_SO_STATISTICS: { 119 struct pipe_query_data_so_statistics *so_stats = &result->so_statistics; 120 so_stats->num_primitives_written = 121 pq->result.coreFE.SoNumPrimsWritten[index]; 122 so_stats->primitives_storage_needed = 123 pq->result.coreFE.SoPrimStorageNeeded[index]; 124 } break; 125 case PIPE_QUERY_TIMESTAMP_DISJOINT: 126 /* os_get_time_nano returns nanoseconds */ 127 result->timestamp_disjoint.frequency = UINT64_C(1000000000); 128 result->timestamp_disjoint.disjoint = FALSE; 129 break; 130 case PIPE_QUERY_PIPELINE_STATISTICS: { 131 struct pipe_query_data_pipeline_statistics *p_stats = 132 &result->pipeline_statistics; 133 p_stats->ia_vertices = pq->result.coreFE.IaVertices; 134 p_stats->ia_primitives = pq->result.coreFE.IaPrimitives; 135 p_stats->vs_invocations = pq->result.coreFE.VsInvocations; 136 p_stats->gs_invocations = pq->result.coreFE.GsInvocations; 137 p_stats->gs_primitives = pq->result.coreFE.GsPrimitives; 138 p_stats->c_invocations = pq->result.coreFE.CPrimitives; 139 p_stats->c_primitives = pq->result.coreFE.CPrimitives; 140 p_stats->ps_invocations = pq->result.core.PsInvocations; 141 p_stats->hs_invocations = pq->result.coreFE.HsInvocations; 142 p_stats->ds_invocations = pq->result.coreFE.DsInvocations; 143 p_stats->cs_invocations = pq->result.core.CsInvocations; 144 } break; 145 case PIPE_QUERY_SO_OVERFLOW_PREDICATE: { 146 uint64_t num_primitives_written = 147 pq->result.coreFE.SoNumPrimsWritten[index]; 148 uint64_t primitives_storage_needed = 149 pq->result.coreFE.SoPrimStorageNeeded[index]; 150 result->b = num_primitives_written > primitives_storage_needed; 151 } 152 break; 153 default: 154 assert(0 && "Unsupported query"); 155 break; 156 } 157 158 return TRUE; 159} 160 161static boolean 162swr_begin_query(struct pipe_context *pipe, struct pipe_query *q) 163{ 164 struct swr_context *ctx = swr_context(pipe); 165 struct swr_query *pq = swr_query(q); 166 167 /* Initialize Results */ 168 memset(&pq->result, 0, sizeof(pq->result)); 169 switch (pq->type) { 170 case PIPE_QUERY_GPU_FINISHED: 171 case PIPE_QUERY_TIMESTAMP: 172 /* nothing to do, but don't want the default */ 173 break; 174 case PIPE_QUERY_TIME_ELAPSED: 175 pq->result.timestamp_start = swr_get_timestamp(pipe->screen); 176 break; 177 default: 178 /* Core counters required. Update draw context with location to 179 * store results. */ 180 swr_update_draw_context(ctx, &pq->result); 181 182 /* Only change stat collection if there are no active queries */ 183 if (ctx->active_queries == 0) { 184 ctx->api.pfnSwrEnableStatsFE(ctx->swrContext, TRUE); 185 ctx->api.pfnSwrEnableStatsBE(ctx->swrContext, TRUE); 186 } 187 ctx->active_queries++; 188 break; 189 } 190 191 192 return true; 193} 194 195static bool 196swr_end_query(struct pipe_context *pipe, struct pipe_query *q) 197{ 198 struct swr_context *ctx = swr_context(pipe); 199 struct swr_query *pq = swr_query(q); 200 201 switch (pq->type) { 202 case PIPE_QUERY_GPU_FINISHED: 203 /* nothing to do, but don't want the default */ 204 break; 205 case PIPE_QUERY_TIMESTAMP: 206 case PIPE_QUERY_TIME_ELAPSED: 207 pq->result.timestamp_end = swr_get_timestamp(pipe->screen); 208 break; 209 default: 210 /* Stats are updated asynchronously, a fence is used to signal 211 * completion. */ 212 if (!pq->fence) { 213 struct swr_screen *screen = swr_screen(pipe->screen); 214 swr_fence_reference(pipe->screen, &pq->fence, screen->flush_fence); 215 } 216 swr_fence_submit(ctx, pq->fence); 217 218 /* Only change stat collection if there are no active queries */ 219 ctx->active_queries--; 220 if (ctx->active_queries == 0) { 221 ctx->api.pfnSwrEnableStatsFE(ctx->swrContext, FALSE); 222 ctx->api.pfnSwrEnableStatsBE(ctx->swrContext, FALSE); 223 } 224 225 break; 226 } 227 228 return true; 229} 230 231 232boolean 233swr_check_render_cond(struct pipe_context *pipe) 234{ 235 struct swr_context *ctx = swr_context(pipe); 236 boolean b, wait; 237 uint64_t result; 238 239 if (!ctx->render_cond_query) 240 return TRUE; /* no query predicate, draw normally */ 241 242 wait = (ctx->render_cond_mode == PIPE_RENDER_COND_WAIT 243 || ctx->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT); 244 245 b = pipe->get_query_result( 246 pipe, ctx->render_cond_query, wait, (union pipe_query_result *)&result); 247 if (b) 248 return ((!result) == ctx->render_cond_cond); 249 else 250 return TRUE; 251} 252 253 254static void 255swr_set_active_query_state(struct pipe_context *pipe, boolean enable) 256{ 257} 258 259void 260swr_query_init(struct pipe_context *pipe) 261{ 262 struct swr_context *ctx = swr_context(pipe); 263 264 pipe->create_query = swr_create_query; 265 pipe->destroy_query = swr_destroy_query; 266 pipe->begin_query = swr_begin_query; 267 pipe->end_query = swr_end_query; 268 pipe->get_query_result = swr_get_query_result; 269 pipe->set_active_query_state = swr_set_active_query_state; 270 271 ctx->active_queries = 0; 272} 273