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