1/* 2 * Copyright © 2019 Intel Corporation 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 shall be included 12 * in all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 * DEALINGS IN THE SOFTWARE. 21 */ 22 23/** 24 * Intel Performance query interface to gallium. 25 */ 26 27#include "st_debug.h" 28#include "st_context.h" 29#include "st_cb_bitmap.h" 30#include "st_cb_perfquery.h" 31#include "st_util.h" 32 33#include "util/bitset.h" 34 35#include "pipe/p_context.h" 36#include "pipe/p_screen.h" 37#include "util/u_memory.h" 38 39bool 40st_have_perfquery(struct st_context *st) 41{ 42 struct pipe_context *pipe = st->pipe; 43 44 return pipe->init_intel_perf_query_info && pipe->get_intel_perf_query_info && 45 pipe->get_intel_perf_query_counter_info && 46 pipe->new_intel_perf_query_obj && pipe->begin_intel_perf_query && 47 pipe->end_intel_perf_query && pipe->delete_intel_perf_query && 48 pipe->wait_intel_perf_query && pipe->is_intel_perf_query_ready && 49 pipe->get_intel_perf_query_data; 50} 51 52static unsigned 53st_InitPerfQueryInfo(struct gl_context *ctx) 54{ 55 struct pipe_context *pipe = st_context(ctx)->pipe; 56 57 return pipe->init_intel_perf_query_info(pipe); 58} 59 60static void 61st_GetPerfQueryInfo(struct gl_context *ctx, 62 unsigned query_index, 63 const char **name, 64 GLuint *data_size, 65 GLuint *n_counters, 66 GLuint *n_active) 67{ 68 struct pipe_context *pipe = st_context(ctx)->pipe; 69 70 pipe->get_intel_perf_query_info(pipe, query_index, name, data_size, 71 n_counters, n_active); 72} 73 74static uint32_t 75pipe_counter_type_enum_to_gl_type(enum pipe_perf_counter_type type) 76{ 77 switch (type) { 78 case PIPE_PERF_COUNTER_TYPE_EVENT: return GL_PERFQUERY_COUNTER_EVENT_INTEL; 79 case PIPE_PERF_COUNTER_TYPE_DURATION_NORM: return GL_PERFQUERY_COUNTER_DURATION_NORM_INTEL; 80 case PIPE_PERF_COUNTER_TYPE_DURATION_RAW: return GL_PERFQUERY_COUNTER_DURATION_RAW_INTEL; 81 case PIPE_PERF_COUNTER_TYPE_THROUGHPUT: return GL_PERFQUERY_COUNTER_THROUGHPUT_INTEL; 82 case PIPE_PERF_COUNTER_TYPE_RAW: return GL_PERFQUERY_COUNTER_RAW_INTEL; 83 case PIPE_PERF_COUNTER_TYPE_TIMESTAMP: return GL_PERFQUERY_COUNTER_TIMESTAMP_INTEL; 84 default: 85 unreachable("Unknown counter type"); 86 } 87} 88 89static uint32_t 90pipe_counter_data_type_to_gl_type(enum pipe_perf_counter_data_type type) 91{ 92 switch (type) { 93 case PIPE_PERF_COUNTER_DATA_TYPE_BOOL32: return GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL; 94 case PIPE_PERF_COUNTER_DATA_TYPE_UINT32: return GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL; 95 case PIPE_PERF_COUNTER_DATA_TYPE_UINT64: return GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL; 96 case PIPE_PERF_COUNTER_DATA_TYPE_FLOAT: return GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL; 97 case PIPE_PERF_COUNTER_DATA_TYPE_DOUBLE: return GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL; 98 default: 99 unreachable("Unknown counter data type"); 100 } 101} 102 103static void 104st_GetPerfCounterInfo(struct gl_context *ctx, 105 unsigned query_index, 106 unsigned counter_index, 107 const char **name, 108 const char **desc, 109 GLuint *offset, 110 GLuint *data_size, 111 GLuint *type_enum, 112 GLuint *data_type_enum, 113 GLuint64 *raw_max) 114{ 115 struct pipe_context *pipe = st_context(ctx)->pipe; 116 uint32_t pipe_type_enum; 117 uint32_t pipe_data_type_enum; 118 119 pipe->get_intel_perf_query_counter_info(pipe, query_index, counter_index, 120 name, desc, offset, data_size, 121 &pipe_type_enum, &pipe_data_type_enum, raw_max); 122 *type_enum = pipe_counter_type_enum_to_gl_type(pipe_type_enum); 123 *data_type_enum = pipe_counter_data_type_to_gl_type(pipe_data_type_enum); 124} 125 126static void 127st_DeletePerfQuery(struct gl_context *ctx, struct gl_perf_query_object *o) 128{ 129 struct pipe_context *pipe = st_context(ctx)->pipe; 130 131 /* We can assume that the frontend waits for a query to complete 132 * before ever calling into here, so we don't have to worry about 133 * deleting an in-flight query object. 134 */ 135 assert(!o->Active); 136 assert(!o->Used || o->Ready); 137 138 pipe->delete_intel_perf_query(pipe, (struct pipe_query *)o); 139} 140 141static bool 142st_BeginPerfQuery(struct gl_context *ctx, struct gl_perf_query_object *o) 143{ 144 struct pipe_context *pipe = st_context(ctx)->pipe; 145 146 /* We can assume the frontend hides mistaken attempts to Begin a 147 * query object multiple times before its End. Similarly if an 148 * application reuses a query object before results have arrived 149 * the frontend will wait for prior results so we don't need 150 * to support abandoning in-flight results. 151 */ 152 assert(!o->Active); 153 assert(!o->Used || o->Ready); /* no in-flight query to worry about */ 154 155 return pipe->begin_intel_perf_query(pipe, (struct pipe_query *)o); 156} 157 158static void 159st_EndPerfQuery(struct gl_context *ctx, struct gl_perf_query_object *o) 160{ 161 struct pipe_context *pipe = st_context(ctx)->pipe; 162 163 pipe->end_intel_perf_query(pipe, (struct pipe_query *)o); 164} 165 166static void 167st_WaitPerfQuery(struct gl_context *ctx, struct gl_perf_query_object *o) 168{ 169 struct pipe_context *pipe = st_context(ctx)->pipe; 170 171 assert(!o->Ready); 172 173 pipe->wait_intel_perf_query(pipe, (struct pipe_query *)o); 174} 175 176static bool 177st_IsPerfQueryReady(struct gl_context *ctx, struct gl_perf_query_object *o) 178{ 179 struct pipe_context *pipe = st_context(ctx)->pipe; 180 181 if (o->Ready) 182 return true; 183 184 return pipe->is_intel_perf_query_ready(pipe, (struct pipe_query *)o); 185} 186 187static bool 188st_GetPerfQueryData(struct gl_context *ctx, 189 struct gl_perf_query_object *o, 190 GLsizei data_size, 191 GLuint *data, 192 GLuint *bytes_written) 193{ 194 struct pipe_context *pipe = st_context(ctx)->pipe; 195 196 assert(st_IsPerfQueryReady(ctx, o)); 197 198 /* We expect that the frontend only calls this hook when it knows 199 * that results are available. 200 */ 201 assert(o->Ready); 202 203 return pipe->get_intel_perf_query_data(pipe, (struct pipe_query *)o, 204 data_size, data, bytes_written); 205} 206 207static struct gl_perf_query_object * 208st_NewPerfQueryObject(struct gl_context *ctx, unsigned query_index) 209{ 210 struct pipe_context *pipe = st_context(ctx)->pipe; 211 struct pipe_query *q; 212 213 q = pipe->new_intel_perf_query_obj(pipe, query_index); 214 215 return (struct gl_perf_query_object *)q; 216} 217 218void st_init_perfquery_functions(struct dd_function_table *functions) 219{ 220 functions->InitPerfQueryInfo = st_InitPerfQueryInfo; 221 functions->GetPerfQueryInfo = st_GetPerfQueryInfo; 222 functions->GetPerfCounterInfo = st_GetPerfCounterInfo; 223 functions->NewPerfQueryObject = st_NewPerfQueryObject; 224 functions->DeletePerfQuery = st_DeletePerfQuery; 225 functions->BeginPerfQuery = st_BeginPerfQuery; 226 functions->EndPerfQuery = st_EndPerfQuery; 227 functions->WaitPerfQuery = st_WaitPerfQuery; 228 functions->IsPerfQueryReady = st_IsPerfQueryReady; 229 functions->GetPerfQueryData = st_GetPerfQueryData; 230} 231