| /* |
| * Copyright © 2019 Intel Corporation |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included |
| * in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| * DEALINGS IN THE SOFTWARE. |
| */ |
| |
| /** |
| * Intel Performance query interface to gallium. |
| */ |
| |
| #include "st_debug.h" |
| #include "st_context.h" |
| #include "st_cb_bitmap.h" |
| #include "st_cb_perfquery.h" |
| #include "st_util.h" |
| |
| #include "util/bitset.h" |
| |
| #include "pipe/p_context.h" |
| #include "pipe/p_screen.h" |
| #include "util/u_memory.h" |
| |
| bool |
| st_have_perfquery(struct st_context *st) |
| { |
| struct pipe_context *pipe = st->pipe; |
| |
| return pipe->init_intel_perf_query_info && pipe->get_intel_perf_query_info && |
| pipe->get_intel_perf_query_counter_info && |
| pipe->new_intel_perf_query_obj && pipe->begin_intel_perf_query && |
| pipe->end_intel_perf_query && pipe->delete_intel_perf_query && |
| pipe->wait_intel_perf_query && pipe->is_intel_perf_query_ready && |
| pipe->get_intel_perf_query_data; |
| } |
| |
| static unsigned |
| st_InitPerfQueryInfo(struct gl_context *ctx) |
| { |
| struct pipe_context *pipe = st_context(ctx)->pipe; |
| |
| return pipe->init_intel_perf_query_info(pipe); |
| } |
| |
| static void |
| st_GetPerfQueryInfo(struct gl_context *ctx, |
| unsigned query_index, |
| const char **name, |
| GLuint *data_size, |
| GLuint *n_counters, |
| GLuint *n_active) |
| { |
| struct pipe_context *pipe = st_context(ctx)->pipe; |
| |
| pipe->get_intel_perf_query_info(pipe, query_index, name, data_size, |
| n_counters, n_active); |
| } |
| |
| static uint32_t |
| pipe_counter_type_enum_to_gl_type(enum pipe_perf_counter_type type) |
| { |
| switch (type) { |
| case PIPE_PERF_COUNTER_TYPE_EVENT: return GL_PERFQUERY_COUNTER_EVENT_INTEL; |
| case PIPE_PERF_COUNTER_TYPE_DURATION_NORM: return GL_PERFQUERY_COUNTER_DURATION_NORM_INTEL; |
| case PIPE_PERF_COUNTER_TYPE_DURATION_RAW: return GL_PERFQUERY_COUNTER_DURATION_RAW_INTEL; |
| case PIPE_PERF_COUNTER_TYPE_THROUGHPUT: return GL_PERFQUERY_COUNTER_THROUGHPUT_INTEL; |
| case PIPE_PERF_COUNTER_TYPE_RAW: return GL_PERFQUERY_COUNTER_RAW_INTEL; |
| case PIPE_PERF_COUNTER_TYPE_TIMESTAMP: return GL_PERFQUERY_COUNTER_TIMESTAMP_INTEL; |
| default: |
| unreachable("Unknown counter type"); |
| } |
| } |
| |
| static uint32_t |
| pipe_counter_data_type_to_gl_type(enum pipe_perf_counter_data_type type) |
| { |
| switch (type) { |
| case PIPE_PERF_COUNTER_DATA_TYPE_BOOL32: return GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL; |
| case PIPE_PERF_COUNTER_DATA_TYPE_UINT32: return GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL; |
| case PIPE_PERF_COUNTER_DATA_TYPE_UINT64: return GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL; |
| case PIPE_PERF_COUNTER_DATA_TYPE_FLOAT: return GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL; |
| case PIPE_PERF_COUNTER_DATA_TYPE_DOUBLE: return GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL; |
| default: |
| unreachable("Unknown counter data type"); |
| } |
| } |
| |
| 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) |
| { |
| struct pipe_context *pipe = st_context(ctx)->pipe; |
| uint32_t pipe_type_enum; |
| uint32_t pipe_data_type_enum; |
| |
| pipe->get_intel_perf_query_counter_info(pipe, query_index, counter_index, |
| name, desc, offset, data_size, |
| &pipe_type_enum, &pipe_data_type_enum, raw_max); |
| *type_enum = pipe_counter_type_enum_to_gl_type(pipe_type_enum); |
| *data_type_enum = pipe_counter_data_type_to_gl_type(pipe_data_type_enum); |
| } |
| |
| static void |
| st_DeletePerfQuery(struct gl_context *ctx, struct gl_perf_query_object *o) |
| { |
| struct pipe_context *pipe = st_context(ctx)->pipe; |
| |
| /* We can assume that the frontend waits for a query to complete |
| * before ever calling into here, so we don't have to worry about |
| * deleting an in-flight query object. |
| */ |
| assert(!o->Active); |
| assert(!o->Used || o->Ready); |
| |
| pipe->delete_intel_perf_query(pipe, (struct pipe_query *)o); |
| } |
| |
| static bool |
| st_BeginPerfQuery(struct gl_context *ctx, struct gl_perf_query_object *o) |
| { |
| struct pipe_context *pipe = st_context(ctx)->pipe; |
| |
| /* We can assume the frontend hides mistaken attempts to Begin a |
| * query object multiple times before its End. Similarly if an |
| * application reuses a query object before results have arrived |
| * the frontend will wait for prior results so we don't need |
| * to support abandoning in-flight results. |
| */ |
| assert(!o->Active); |
| assert(!o->Used || o->Ready); /* no in-flight query to worry about */ |
| |
| pipe->begin_intel_perf_query(pipe, (struct pipe_query *)o); |
| |
| return true; |
| } |
| |
| static void |
| st_EndPerfQuery(struct gl_context *ctx, struct gl_perf_query_object *o) |
| { |
| struct pipe_context *pipe = st_context(ctx)->pipe; |
| |
| pipe->end_intel_perf_query(pipe, (struct pipe_query *)o); |
| } |
| |
| static void |
| st_WaitPerfQuery(struct gl_context *ctx, struct gl_perf_query_object *o) |
| { |
| struct pipe_context *pipe = st_context(ctx)->pipe; |
| |
| assert(!o->Ready); |
| |
| pipe->wait_intel_perf_query(pipe, (struct pipe_query *)o); |
| } |
| |
| static bool |
| st_IsPerfQueryReady(struct gl_context *ctx, struct gl_perf_query_object *o) |
| { |
| struct pipe_context *pipe = st_context(ctx)->pipe; |
| |
| if (o->Ready) |
| return true; |
| |
| return pipe->is_intel_perf_query_ready(pipe, (struct pipe_query *)o); |
| } |
| |
| static void |
| st_GetPerfQueryData(struct gl_context *ctx, |
| struct gl_perf_query_object *o, |
| GLsizei data_size, |
| GLuint *data, |
| GLuint *bytes_written) |
| { |
| struct pipe_context *pipe = st_context(ctx)->pipe; |
| |
| assert(st_IsPerfQueryReady(ctx, o)); |
| |
| /* We expect that the frontend only calls this hook when it knows |
| * that results are available. |
| */ |
| assert(o->Ready); |
| |
| pipe->get_intel_perf_query_data(pipe, (struct pipe_query *)o, data_size, data, |
| bytes_written); |
| } |
| |
| static struct gl_perf_query_object * |
| st_NewPerfQueryObject(struct gl_context *ctx, unsigned query_index) |
| { |
| struct pipe_context *pipe = st_context(ctx)->pipe; |
| struct pipe_query *q; |
| |
| q = pipe->new_intel_perf_query_obj(pipe, query_index); |
| |
| return (struct gl_perf_query_object *)q; |
| } |
| |
| void st_init_perfquery_functions(struct dd_function_table *functions) |
| { |
| functions->InitPerfQueryInfo = st_InitPerfQueryInfo; |
| functions->GetPerfQueryInfo = st_GetPerfQueryInfo; |
| functions->GetPerfCounterInfo = st_GetPerfCounterInfo; |
| functions->NewPerfQueryObject = st_NewPerfQueryObject; |
| functions->DeletePerfQuery = st_DeletePerfQuery; |
| functions->BeginPerfQuery = st_BeginPerfQuery; |
| functions->EndPerfQuery = st_EndPerfQuery; |
| functions->WaitPerfQuery = st_WaitPerfQuery; |
| functions->IsPerfQueryReady = st_IsPerfQueryReady; |
| functions->GetPerfQueryData = st_GetPerfQueryData; |
| } |