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 
39 bool
st_have_perfquery(struct st_context * st)40 st_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 
52 static unsigned
st_InitPerfQueryInfo(struct gl_context * ctx)53 st_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 
60 static void
st_GetPerfQueryInfo(struct gl_context * ctx,unsigned query_index,const char ** name,GLuint * data_size,GLuint * n_counters,GLuint * n_active)61 st_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 
74 static uint32_t
pipe_counter_type_enum_to_gl_type(enum pipe_perf_counter_type type)75 pipe_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 
89 static uint32_t
pipe_counter_data_type_to_gl_type(enum pipe_perf_counter_data_type type)90 pipe_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 
103 static void
st_GetPerfCounterInfo(struct gl_context * ctx,unsigned query_index,unsigned counter_index,const char ** name,const char ** desc,GLuint * offset,GLuint * data_size,GLuint * type_enum,GLuint * data_type_enum,GLuint64 * raw_max)104 st_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 
126 static void
st_DeletePerfQuery(struct gl_context * ctx,struct gl_perf_query_object * o)127 st_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 
141 static bool
st_BeginPerfQuery(struct gl_context * ctx,struct gl_perf_query_object * o)142 st_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 
158 static void
st_EndPerfQuery(struct gl_context * ctx,struct gl_perf_query_object * o)159 st_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 
166 static void
st_WaitPerfQuery(struct gl_context * ctx,struct gl_perf_query_object * o)167 st_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 
176 static bool
st_IsPerfQueryReady(struct gl_context * ctx,struct gl_perf_query_object * o)177 st_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 
187 static bool
st_GetPerfQueryData(struct gl_context * ctx,struct gl_perf_query_object * o,GLsizei data_size,GLuint * data,GLuint * bytes_written)188 st_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 
207 static struct gl_perf_query_object *
st_NewPerfQueryObject(struct gl_context * ctx,unsigned query_index)208 st_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 
st_init_perfquery_functions(struct dd_function_table * functions)218 void 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