/************************************************************************** * * Copyright 2015 Alexander Trukhin * All Rights Reserved. * * 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. * **************************************************************************/ #pragma once #include #include /** * Profiling boundary. */ enum QueryBoundary { QUERY_BOUNDARY_DRAWCALL = 0, /**< draw call boundary */ QUERY_BOUNDARY_FRAME, /**< frame boundary */ QUERY_BOUNDARY_CALL, /**< any call boundary */ QUERY_BOUNDARY_LIST_END }; /** * Numeric type of the metric. */ enum MetricNumType { CNT_NUM_UINT = 0, CNT_NUM_FLOAT, CNT_NUM_UINT64, CNT_NUM_DOUBLE, CNT_NUM_BOOL, CNT_NUM_INT64 }; /** * Type of data metric represents. */ enum MetricType { CNT_TYPE_GENERIC = 0, /**< generally a number, comparable type */ CNT_TYPE_NUM, /**< number, not necessarily comparable (e.g. event number) */ CNT_TYPE_DURATION, /**< duration */ CNT_TYPE_PERCENT, /**< percentage */ CNT_TYPE_TIMESTAMP, /**< timestamp (e.g. GL_TIMESTAMP in OpenGL) */ CNT_TYPE_OTHER /**< not listed above */ }; /** * Metric interface. * * Each metric can be uniquely identified by a group id and a metric id. * Each backend is assumed to implement its own version of Metric. It is also * supposed to provide metric groups and corresponding metrics. * This interface is used to communicate with backend and can be used * to store internal data in backend. * * It is generally a good idea to cache some parameters (e.g. numeric type). */ class Metric { public: virtual ~Metric() {} /** * Returns metric id */ virtual unsigned id() = 0; /** * Returns metric group id */ virtual unsigned groupId() = 0; /** * Returns metric name string */ virtual std::string name() = 0; /** * Returns metric description string (or an empty string if not available) */ virtual std::string description() = 0; /** * Returns metric numeric type */ virtual MetricNumType numType() = 0; /** * Returns data type metric represents */ virtual MetricType type() = 0; }; /** * Callbacks for use in backend interface. * int error : error code (0 - no error) * void* userData : arbitrary pointer */ typedef void (*enumGroupsCallback)(unsigned group, int error, void* userData); typedef void (*enumMetricsCallback)(Metric* metric, int error, void* userData); typedef void (*enumDataCallback)(Metric* metric, int event, void* data, int error, void* userData); /** * Backend interface. * * Abstraction for metric-collection system. * Such system is supposed to have its own version of MetricBackend. * Backend can be used to query available metrics, to profile calls/frames and * to collect metrics. * Backend is responsible for storing metric data. * * Unfortunately, not all collection systems allow to collect all metrics * at the same time. Therefore multiple passes are needed, this interface provides * the mean to implement such behaviour. * * * Typical workflow example: * MetricBackend* backend; * backend->enableMetric(...); * ... * backend->enableMetric(...); * for (i=0; i < backend->generatePasses(); i++) { * backend->beginPass(); * * backend->beginQuery(QUERY_BOUNDARY_FRAME); * * backend->beginQuery(QUERY_BOUNDARY_CALL or QUERY_BOUNDARY_DRAWCALL); * ... profiled call ... * backend->endQuery(QUERY_BOUNDARY_CALL or QUERY_BOUNDARY_DRAWCALL); * * ... * * backend->beginQuery(QUERY_BOUNDARY_CALL or QUERY_BOUNDARY_DRAWCALL); * ... profiled call ... * backend->endQuery(QUERY_BOUNDARY_CALL or QUERY_BOUNDARY_DRAWCALL); * * backend->endQuery(QUERY_BOUNDARY_FRAME); * * ... following frames ... * * backend->endPass(); * } * // collect data * * * It is generally a good idea to implement MetricBackend as a singleton. */ class MetricBackend { public: virtual ~MetricBackend() {} /** * Returns true if MetricBackend is supported on current HW. */ virtual bool isSupported() = 0; /** * Enumerates metric groups, calls callback for each group. */ virtual void enumGroups(enumGroupsCallback callback, void* userData = nullptr) = 0; /** * Enumerates metrics in specified group, calls callback for each metric. * Callback receives pointer to the metric object among other params. * Metric object is an object of class derived from Metric. */ virtual void enumMetrics(unsigned group, enumMetricsCallback callback, void* userData = nullptr) = 0; /** * Returns group name string (or an empty string if not available). */ virtual std::string getGroupName(unsigned group) = 0; /** * Returns pointer to the metric object with given group id, metric id. * Metric object is an object of class derived from Metric. */ virtual std::unique_ptr getMetricById(unsigned groupId, unsigned metricId) = 0; /** * Returns pointer to the metric object with given metric name string. * Metric object is an object of class derived from Metric. */ virtual std::unique_ptr getMetricByName(std::string metricName) = 0; /** * Adds given metric object to the internal list of metrics * to be profiled. * pollingRule sets the boundary for collecting metric * Returns error code (0 - no error). */ virtual int enableMetric(Metric* metric, QueryBoundary pollingRule = QUERY_BOUNDARY_DRAWCALL) = 0; /** * Generates passes based on enabled metrics. * Returns number of generated passes. */ virtual unsigned generatePasses() = 0; /** * Begins pass. Subsequent calls begin next passes. * A pass needs to be ended before starting a new one. */ virtual void beginPass() = 0; /** * Ends pass. */ virtual void endPass() = 0; /** * Pause pass with all the queries in progress. * Backend decides what to do with the data of interrupted * query. * Can be used before the context switch in OpenGl. */ virtual void pausePass() = 0; /** * Continue profiling the pass after pausePass(). * Backend decides whether to reprofile interrupted by pausePass() query. * Can be used after the context switch in OpenGl. */ virtual void continuePass() = 0; /** * Begins query (profiles unit, i.e. frames or calls). Subsequent calls * begin next queries. * Parameter boundary should be set to the type of boundary beginQuery/endQuery * constructions enclose. * A query needs to be ended before starting a new one. */ virtual void beginQuery(QueryBoundary boundary = QUERY_BOUNDARY_DRAWCALL) = 0; /** * Ends query. * Parameter boundary should be set to the type of boundary beginQuery/endQuery * constructions enclose. */ virtual void endQuery(QueryBoundary boundary = QUERY_BOUNDARY_DRAWCALL) = 0; /** * Enumerates collected metrics data for a given query id and given * type of boundary. * Query ids begin with 0 for first query. * Metric data is passed to callback. * * The order in which metrics are returned can differ from the one in which * metrics were enabled (via enableMetric(...)) . However, it should be * guaranteed that order is the same for every query. */ virtual void enumDataQueryId(unsigned id, enumDataCallback callback, QueryBoundary boundary, void* userData = nullptr) = 0; /** * Returns number of passes generated by generatePasses(...). * If generatePasses(...) was not called returns 1. */ virtual unsigned getNumPasses() = 0; };