1/* 2 * Copyright (C) 2014 Rob Clark <robclark@freedesktop.org> 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 FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 * 23 * Authors: 24 * Rob Clark <robclark@freedesktop.org> 25 */ 26 27#include "pipe/p_state.h" 28#include "util/os_time.h" 29#include "util/u_inlines.h" 30#include "util/u_memory.h" 31#include "util/u_string.h" 32 33#include "freedreno_context.h" 34#include "freedreno_query_sw.h" 35#include "freedreno_util.h" 36 37/* 38 * SW Queries: 39 * 40 * In the core, we have some support for basic sw counters 41 */ 42 43static void 44fd_sw_destroy_query(struct fd_context *ctx, struct fd_query *q) 45{ 46 struct fd_sw_query *sq = fd_sw_query(q); 47 free(sq); 48} 49 50static uint64_t 51read_counter(struct fd_context *ctx, int type) assert_dt 52{ 53 switch (type) { 54 case PIPE_QUERY_PRIMITIVES_GENERATED: 55 return ctx->stats.prims_generated; 56 case PIPE_QUERY_PRIMITIVES_EMITTED: 57 return ctx->stats.prims_emitted; 58 case FD_QUERY_DRAW_CALLS: 59 return ctx->stats.draw_calls; 60 case FD_QUERY_BATCH_TOTAL: 61 return ctx->stats.batch_total; 62 case FD_QUERY_BATCH_SYSMEM: 63 return ctx->stats.batch_sysmem; 64 case FD_QUERY_BATCH_GMEM: 65 return ctx->stats.batch_gmem; 66 case FD_QUERY_BATCH_NONDRAW: 67 return ctx->stats.batch_nondraw; 68 case FD_QUERY_BATCH_RESTORE: 69 return ctx->stats.batch_restore; 70 case FD_QUERY_STAGING_UPLOADS: 71 return ctx->stats.staging_uploads; 72 case FD_QUERY_SHADOW_UPLOADS: 73 return ctx->stats.shadow_uploads; 74 case FD_QUERY_VS_REGS: 75 return ctx->stats.vs_regs; 76 case FD_QUERY_FS_REGS: 77 return ctx->stats.fs_regs; 78 } 79 return 0; 80} 81 82static bool 83is_time_rate_query(struct fd_query *q) 84{ 85 switch (q->type) { 86 case FD_QUERY_BATCH_TOTAL: 87 case FD_QUERY_BATCH_SYSMEM: 88 case FD_QUERY_BATCH_GMEM: 89 case FD_QUERY_BATCH_NONDRAW: 90 case FD_QUERY_BATCH_RESTORE: 91 case FD_QUERY_STAGING_UPLOADS: 92 case FD_QUERY_SHADOW_UPLOADS: 93 return true; 94 default: 95 return false; 96 } 97} 98 99static bool 100is_draw_rate_query(struct fd_query *q) 101{ 102 switch (q->type) { 103 case FD_QUERY_VS_REGS: 104 case FD_QUERY_FS_REGS: 105 return true; 106 default: 107 return false; 108 } 109} 110 111static void 112fd_sw_begin_query(struct fd_context *ctx, struct fd_query *q) assert_dt 113{ 114 struct fd_sw_query *sq = fd_sw_query(q); 115 116 ctx->stats_users++; 117 118 sq->begin_value = read_counter(ctx, q->type); 119 if (is_time_rate_query(q)) { 120 sq->begin_time = os_time_get(); 121 } else if (is_draw_rate_query(q)) { 122 sq->begin_time = ctx->stats.draw_calls; 123 } 124} 125 126static void 127fd_sw_end_query(struct fd_context *ctx, struct fd_query *q) assert_dt 128{ 129 struct fd_sw_query *sq = fd_sw_query(q); 130 131 assert(ctx->stats_users > 0); 132 ctx->stats_users--; 133 134 sq->end_value = read_counter(ctx, q->type); 135 if (is_time_rate_query(q)) { 136 sq->end_time = os_time_get(); 137 } else if (is_draw_rate_query(q)) { 138 sq->end_time = ctx->stats.draw_calls; 139 } 140} 141 142static bool 143fd_sw_get_query_result(struct fd_context *ctx, struct fd_query *q, bool wait, 144 union pipe_query_result *result) 145{ 146 struct fd_sw_query *sq = fd_sw_query(q); 147 148 result->u64 = sq->end_value - sq->begin_value; 149 150 if (is_time_rate_query(q)) { 151 double fps = 152 (result->u64 * 1000000) / (double)(sq->end_time - sq->begin_time); 153 result->u64 = (uint64_t)fps; 154 } else if (is_draw_rate_query(q)) { 155 double avg = 156 ((double)result->u64) / (double)(sq->end_time - sq->begin_time); 157 result->f = avg; 158 } 159 160 return true; 161} 162 163static const struct fd_query_funcs sw_query_funcs = { 164 .destroy_query = fd_sw_destroy_query, 165 .begin_query = fd_sw_begin_query, 166 .end_query = fd_sw_end_query, 167 .get_query_result = fd_sw_get_query_result, 168}; 169 170struct fd_query * 171fd_sw_create_query(struct fd_context *ctx, unsigned query_type, unsigned index) 172{ 173 struct fd_sw_query *sq; 174 struct fd_query *q; 175 176 switch (query_type) { 177 case PIPE_QUERY_PRIMITIVES_GENERATED: 178 case PIPE_QUERY_PRIMITIVES_EMITTED: 179 case FD_QUERY_DRAW_CALLS: 180 case FD_QUERY_BATCH_TOTAL: 181 case FD_QUERY_BATCH_SYSMEM: 182 case FD_QUERY_BATCH_GMEM: 183 case FD_QUERY_BATCH_NONDRAW: 184 case FD_QUERY_BATCH_RESTORE: 185 case FD_QUERY_STAGING_UPLOADS: 186 case FD_QUERY_SHADOW_UPLOADS: 187 case FD_QUERY_VS_REGS: 188 case FD_QUERY_FS_REGS: 189 break; 190 default: 191 return NULL; 192 } 193 194 sq = CALLOC_STRUCT(fd_sw_query); 195 if (!sq) 196 return NULL; 197 198 q = &sq->base; 199 q->funcs = &sw_query_funcs; 200 q->type = query_type; 201 202 return q; 203} 204