You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

797 lines
31 KiB

#ifndef Magnum_DebugTools_FrameProfiler_h
#define Magnum_DebugTools_FrameProfiler_h
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021, 2022, 2023 Vladimír Vondruš <mosra@centrum.cz>
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.
*/
/** @file
* @brief Class @ref Magnum::DebugTools::FrameProfiler, @ref Magnum::DebugTools::FrameProfilerGL
* @m_since{2020,06}
*/
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/Pointer.h>
#include <Corrade/Containers/String.h>
#include "Magnum/Magnum.h"
#include "Magnum/DebugTools/visibility.h"
#ifdef MAGNUM_BUILD_DEPRECATED
/* Measurement used to take a std::string, measurementName() and statistics()
used to be a std::string. Not ideal for the return types, but at least
something. */
#include <Corrade/Containers/StringStl.h>
#endif
namespace Magnum { namespace DebugTools {
/**
@brief Frame profiler
@m_since{2020,06}
A generic implementation of a frame profiler supporting a moving average over
a set of frames as well as delayed measurements to avoid stalls when querying
the results. This class alone doesn't provide any pre-defined measurements, see
for example @ref FrameProfilerGL that provides common measurements like CPU and
GPU time.
@experimental
@section DebugTools-FrameProfiler-usage Basic usage
Measurements are performed by calling @ref beginFrame() and @ref endFrame() at
designated points in the frame:
@snippet DebugTools.cpp FrameProfiler-usage
In order to have stable profiling results, the application needs to redraw
constantly. However for applications that otherwise redraw only on change it
might be wasteful --- to account for this, it's possible to toggle the profiler
operation using @ref enable() / @ref disable() and then
@ref Platform::Sdl2Application::redraw() "redraw()" can be called only if
@ref isEnabled() returns @cpp true @ce.
Data for all measurements is then available through @ref measurementName(),
@ref measurementUnits() and @ref measurementMean(). For a convenient overview
of all measured values you can call @ref statistics() and feed its output to a
UI library or something that can render text. Alternatively, if you don't want
to bother with text rendering, call @ref printStatistics() to have the output
periodically printed to the console. If an interactive terminal is detected,
the output will be colored and refreshing itself in place. Together with the
on-demand profiling, it could look like this, refreshing the output every 10
frames:
@snippet DebugTools.cpp FrameProfiler-usage-console
And here's a sample output on the terminal --- using a fully configured
@link FrameProfilerGL @endlink:
@include debugtools-frameprofiler.ansi
@section DebugTools-FrameProfiler-setup Setting up measurements
Unless you're using this class through @ref FrameProfilerGL, measurements
have to be set up by passing @ref Measurement instances to the @ref setup()
function or to the constructor, together with specifying count of frames for
the moving average. A CPU duration measurements using the @ref std::chrono APIs
over last 50 frames can be done like this:
@snippet DebugTools.cpp FrameProfiler-setup-immediate
In the above case, the measurement result is available immediately on frame
end. That's not always the case, and for example GPU queries need a few frames
delay to avoid stalls from CPU/GPU synchronization. The following snippet sets
up sample count measurement with a delay, using three separate
@ref GL::SampleQuery instances that are cycled through each frame and retrieved
two frames later. The profiler automatically takes care of choosing one of the
three instances for each measurement via additional `current` / `previous`
parameters passed to each callback:
@snippet DebugTools-gl.cpp FrameProfiler-setup-delayed
<b></b>
@m_class{m-block m-warning}
@par Move construction and state pointers in callbacks
The @ref FrameProfiler class is movable, which could potentially mean that
state pointers passed to callback functions become dangling. It's not a
problem in the above snippets because the state is always external to the
instance, but care has to be taken when passing pointers to subclasses.
@par
When setting up measurements from a subclass, it's recommended to always
pass @cpp this @ce as the state pointer. The base class recognizes it
during a move and patches the state to point to the new instance instead.
If you don't or can't use @cpp this @ce as a state pointer, you need to
either provide a dedicated move constructor and assignment to do the
required patching or disable moves altogether to avoid accidents.
*/
class MAGNUM_DEBUGTOOLS_EXPORT FrameProfiler {
public:
/**
* @brief Measurement units
*
* @see @ref Measurement
*/
enum class Units: UnsignedByte {
/**
* Nanoseconds, measuring for example elapsed time. Depending on
* the magnitude, @ref statistics() can show them as microseconds,
* milliseconds or seconds.
*/
Nanoseconds,
/**
* Bytes, measuring for example memory usage, bandwidth. Depending
* on the magnitude, @ref statistics() can show them as kB, MB, GB
* (with a multiplier of 1024).
*/
Bytes,
/**
* Generic count. For discrete values that don't fit any of the
* above. Depending on the magnitude, @ref statistics() can show
* the value as k, M or G (with a multiplier of 1000).
*/
Count,
/**
* Ratio expressed in 1/1000s. @ref statistics() divides the value
* by 1000 and depending on the magnitude it can show it also as k,
* M or G (with a multiplier of 1000).
*/
RatioThousandths,
/**
* Percentage expressed in 1/1000s. @ref statistics() divides the
* value by 1000 and appends a % sign.
*/
PercentageThousandths
};
class Measurement;
/**
* @brief Default constructor
*
* Call @ref setup() to populate the profiler with measurements.
*/
explicit FrameProfiler() noexcept;
/**
* @brief Constructor
*
* Equivalent to default-constructing an instance and calling
* @ref setup() afterwards.
*/
explicit FrameProfiler(Containers::Array<Measurement>&& measurements, UnsignedInt maxFrameCount) noexcept;
/** @overload */
explicit FrameProfiler(std::initializer_list<Measurement> measurements, UnsignedInt maxFrameCount);
/** @brief Copying is not allowed */
FrameProfiler(const FrameProfiler&) = delete;
/** @brief Move constructor */
FrameProfiler(FrameProfiler&&) noexcept;
/** @brief Copying is not allowed */
FrameProfiler& operator=(const FrameProfiler&) = delete;
/** @brief Move assignment */
FrameProfiler& operator=(FrameProfiler&&) noexcept;
/**
* @brief Setup measurements
* @param measurements List of measurements
* @param maxFrameCount Max frame count over which to calculate a
* moving average. Expected to be at least @cpp 1 @ce.
*
* Calling @ref setup() on an already set up profiler will replace
* existing measurements with @p measurements and reset
* @ref measuredFrameCount() back to @cpp 0 @ce.
*/
void setup(Containers::Array<Measurement>&& measurements, UnsignedInt maxFrameCount);
/** @overload */
void setup(std::initializer_list<Measurement> measurements, UnsignedInt maxFrameCount);
/** @brief Whether the profiling is enabled */
bool isEnabled() const { return _enabled; }
/**
* @brief Enable the profiler
*
* The profiler is enabled implicitly after construction. When this
* function is called, it discards all measured data, effectively
* making @ref measuredFrameCount() zero. If you want to reset the
* profiler to measure different values as well, call @ref setup().
*/
void enable();
/**
* @brief Disable the profiler
*
* Disabling the profiler will make @ref beginFrame() and
* @ref endFrame() a no-op, effectively freezing all reported
* measurements until the profiler is enabled again.
*/
void disable();
/**
* @brief Begin a frame
*
* Has to be called at the beginning of a frame and be paired with a
* corresponding @ref endFrame(). Calls @p begin functions in all
* @ref Measurement instances passed to @ref setup(). If the profiler
* is disabled, the function is a no-op.
* @see @ref isEnabled()
*/
void beginFrame();
/**
* @brief End a frame
*
* Has to be called at the end of frame, before buffer swap, and be
* paired with a corresponding @ref beginFrame(). Calls @p end
* functions in all @ref Measurement instances passed to @ref setup()
* and @p query functions on all measurements that are sufficiently
* delayed, saving their output. If the profiler is disabled, the
* function is a no-op.
* @see @ref isEnabled()
*/
void endFrame();
/**
* @brief Max count of measured frames
*
* How many frames to calculate a moving average from. At the beginning
* of a measurement when there's not enough frames, the average is
* calculated only from @ref measuredFrameCount(). Always at least
* @cpp 1 @ce.
*/
UnsignedInt maxFrameCount() const { return _maxFrameCount; }
/**
* @brief Count of measured frames
*
* Count of times @ref endFrame() was called, but at most
* @ref maxFrameCount(), after which the profiler calculates a moving
* average over last @ref maxFrameCount() frames only. Actual data
* availability depends on @ref measurementDelay().
*/
UnsignedInt measuredFrameCount() const { return _measuredFrameCount; }
/**
* @brief Measurement count
*
* Count of @ref Measurement instances passed to @ref setup(). If
* @ref setup() was not called yet, returns @cpp 0 @ce.
*/
UnsignedInt measurementCount() const { return _measurements.size(); }
/**
* @brief Measurement name
*
* The @p id corresponds to the index of the measurement in the list
* passed to @ref setup(). Expects that @p id is less than
* @ref measurementCount(). The returned view is always
* @relativeref{Corrade,Containers::StringViewFlag::NullTerminated};
* @relativeref{Corrade,Containers::StringViewFlag::Global} is set if
* the corresponding @ref Measurement was created with a global
* null-terminated string view.
*/
Containers::StringView measurementName(UnsignedInt id) const;
/**
* @brief Measurement units
*
* The @p id corresponds to the index of the measurement in the list
* passed to @ref setup(). Expects that @p id is less than
* @ref measurementCount().
*/
Units measurementUnits(UnsignedInt id) const;
/**
* @brief Measurement delay
*
* How many @ref beginFrame() / @ref endFrame() call pairs needs to be
* performed before a value for given measurement is available. Always
* at least @cpp 1 @ce. The @p id corresponds to the index of the
* measurement in the list passed to @ref setup(). Expects that @p id
* is less than @ref measurementCount().
*/
UnsignedInt measurementDelay(UnsignedInt id) const;
/**
* @brief Whether given measurement is available
*
* Returns @cpp true @ce if @ref measuredFrameCount() is at least
* @ref measurementDelay() for given @p id, @cpp false @ce otherwise.
* The @p id corresponds to the index of the measurement in the list
* passed to @ref setup(). Expects that @p id is less than
* @ref measurementCount().
*/
bool isMeasurementAvailable(UnsignedInt id) const;
/**
* @brief Measurement data at given frame
*
* A @p frame value of @cpp 0 @ce is the oldest recorded frame and can
* go up to @ref measurementCount() lessened by @ref measurementDelay()
* or @ref maxFrameCount() minus one, whichever is smaller. Expects that
* @p id is less than @ref measurementCount() and at least
* one measurement is available.
* @see @ref isMeasurementAvailable()
*/
UnsignedLong measurementData(UnsignedInt id, UnsignedInt frame) const;
/**
* @brief Measurement mean
*
* Returns a moving average of @f$ n @f$ previous measurements out of
* the total @f$ M @f$ values: @f[
* \bar{x}_\text{SM} = \dfrac{1}{n} \sum\limits_{i=0}^{n-1} x_{M -i}
* @f]
*
* The @p id corresponds to the index of the measurement in the list
* passed to @ref setup(). Expects that @p id is less than
* @ref measurementCount() and that the measurement is available.
* @see @ref isMeasurementAvailable()
*/
Double measurementMean(UnsignedInt id) const;
/**
* @brief Overview of all measurements
*
* Returns a formatted string with names, means and units of all
* measurements in the order they were added. If some measurement data
* is not available yet, prints placeholder values for these.
* @see @ref isMeasurementAvailable(), @ref isEnabled()
*/
Containers::String statistics() const;
/**
* @brief Print an overview of all measurements to a console at given rate
*
* Expected to be called every frame. If profiling is enabled, on every
* `frequency`th frame prints the same information as @ref statistics(),
* but in addition, if the output is a TTY, it's colored and overwrites
* itself instead of filling up the terminal history. If profiling is
* disabled, does nothing.
* @see @ref isMeasurementAvailable(), @ref isEnabled()
* @ref Corrade::Utility::Debug::isTty()
*/
void printStatistics(UnsignedInt frequency) const;
/**
* @brief Print an overview of all measurements to given output at given rate
*
* Compared to @ref printStatistics(UnsignedInt) const prints to given
* @p out (which can be also @ref Corrade::Utility::Warning or
* @ref Corrade::Utility::Error) and uses it to decide whether the
* output is a TTY and whether to print colors.
* @see @ref Corrade::Utility::Debug::isTty(),
* @ref Corrade::Utility::Debug::Flag::DisableColors
*/
void printStatistics(Debug& out, UnsignedInt frequency) const;
/** @overload */
void printStatistics(Debug&& out, UnsignedInt frequency) const {
printStatistics(out, frequency);
}
private:
UnsignedInt delayedCurrentData(UnsignedInt delay) const;
Double measurementMeanInternal(const Measurement& measurement) const;
void printStatisticsInternal(Debug& out) const;
bool _enabled = true;
#ifndef CORRADE_NO_ASSERT
/* Here it shouldn't cause the class to have a different size when
asserts get disabled */
bool _beginFrameCalled{};
#endif
UnsignedInt _maxFrameCount{1}, _measuredFrameCount{};
Containers::Array<Measurement> _measurements;
Containers::Array<UnsignedLong> _data;
};
/**
@brief Measurement
Describes a single measurement passed to @ref FrameProfiler::setup(). See
@ref DebugTools-FrameProfiler-setup for introduction and examples.
*/
class MAGNUM_DEBUGTOOLS_EXPORT FrameProfiler::Measurement {
public:
/**
* @brief Construct an immediate measurement
* @param name Measurement name, used in
* @ref FrameProfiler::measurementName() and
* @ref FrameProfiler::statistics()
* @param units Measurement units, used in
* @ref FrameProfiler::measurementUnits() and
* @ref FrameProfiler::statistics()
* @param begin Function to call at the beginning of a frame
* @param end Function to call at the end of a frame, returning
* the measured value
* @param state State pointer passed to both @p begin and @p end
* as a first argument
*
* If @p name is @relativeref{Corrade,Containers::StringViewFlag::NullTerminated}
* and @relativeref{Corrade::Containers::StringViewFlag,Global}, no
* internal copy of the string is made.
*/
explicit Measurement(Containers::StringView name, Units units, void(*begin)(void*), UnsignedLong(*end)(void*), void* state);
/**
* @brief Construct a delayed measurement
* @param name Measurement name, used in
* @ref FrameProfiler::measurementName() and
* @ref FrameProfiler::statistics()
* @param units Measurement units, used in
* @ref FrameProfiler::measurementUnits() and
* @ref FrameProfiler::statistics()
* @param delay How many @ref FrameProfiler::endFrame() calls has
* to happen before a measured value can be retrieved using
* @p query. Has to be at least @cpp 1 @ce, delay of @cpp 1 @ce is
* equal in behavior to immediate measurements.
* @param begin Function to call at the beginning of a frame.
* Second argument is a `current` index that's guaranteed to be
* less than @p delay and always different in each consecutive
* call.
* @param end Function to call at the end of a frame.
* Second argument is a `current` index that's guaranteed to be
* less than @p delay and always different in each consecutive
* call.
* @param query Function to call to get the measured value. Called
* after @p delay frames. First argument is a `previous` index
* that is the same as the `current` argument passed to a
* corresponding @p begin / @p end function of the measurement to
* query the value of. Second argument is a `current` index that
* corresponds to current frame.
* @param state State pointer passed to both @p begin and @p end
* as a first argument
*
* If @p name is @relativeref{Corrade,Containers::StringViewFlag::NullTerminated}
* and @relativeref{Corrade::Containers::StringViewFlag,Global}, no
* internal copy of the string is made.
*/
explicit Measurement(Containers::StringView name, Units units, UnsignedInt delay, void(*begin)(void*, UnsignedInt), void(*end)(void*, UnsignedInt), UnsignedLong(*query)(void*, UnsignedInt, UnsignedInt), void* state);
private:
friend FrameProfiler;
Containers::String _name;
union {
void(*immediate)(void*);
void(*delayed)(void*, UnsignedInt);
} _begin;
void(*_end)(void*, UnsignedInt);
union {
UnsignedLong(*immediate)(void*);
UnsignedLong(*delayed)(void*, UnsignedInt, UnsignedInt);
} _query;
void* _state;
Units _units;
/* Set to 0 to distinguish immediate measurements (first
constructor), however always used as max(_delay, 1) */
UnsignedInt _delay;
UnsignedInt _current{};
UnsignedLong _movingSum{};
};
/**
@debugoperatorclassenum{FrameProfiler,FrameProfiler::Units}
@m_since{2020,06}
*/
MAGNUM_DEBUGTOOLS_EXPORT Debug& operator<<(Debug& debug, FrameProfiler::Units value);
#ifdef MAGNUM_TARGET_GL
/**
@brief OpenGL frame profiler
@m_since{2020,06}
A @ref FrameProfiler with OpenGL-specific measurements. Instantiate with a
desired subset of measured values and then continue the same way as described
in the @ref DebugTools-FrameProfiler-usage "FrameProfiler usage documentation":
@snippet DebugTools-gl.cpp FrameProfilerGL-usage
If none of @ref Value::GpuDuration, @ref Value::VertexFetchRatio and
@ref Value::PrimitiveClipRatio is not enabled, the class can operate without an
active OpenGL context.
@experimental
*/
class MAGNUM_DEBUGTOOLS_EXPORT FrameProfilerGL: public FrameProfiler {
public:
/**
* @brief Measured value
*
* @see @ref Values, @ref FrameProfilerGL(Values, UnsignedInt),
* @ref setup()
*/
enum class Value: UnsignedShort {
/**
* Measure total frame time (i.e., time between consecutive
* @ref beginFrame() calls). Reported in @ref Units::Nanoseconds
* with a delay of 2 frames. When converted to seconds, the value
* is an inverse of FPS.
*/
FrameTime = 1 << 0,
/**
* Measure CPU frame duration (i.e., CPU time spent between
* @ref beginFrame() and @ref endFrame()). Reported in
* @ref Units::Nanoseconds with a delay of 1 frame.
*/
CpuDuration = 1 << 1,
/**
* Measure GPU frame duration (i.e., time between @ref beginFrame()
* and @ref endFrame()). Reported in @ref Units::Nanoseconds
* with a delay of 3 frames. This value requires an active OpenGL
* context.
* @requires_gl33 Extension @gl_extension{ARB,timer_query}
* @requires_es_extension Extension @gl_extension{EXT,disjoint_timer_query}
* @requires_webgl_extension Extension @webgl_extension{EXT,disjoint_timer_query}
* on WebGL 1, @webgl_extension{EXT,disjoint_timer_query_webgl2}
* on WebGL 2
*/
GpuDuration = 1 << 2,
#ifndef MAGNUM_TARGET_GLES
/**
* Ratio of vertex shader invocations to count of vertices
* submitted. For a non-indexed draw the ratio will be 1, for
* indexed draws ratio is less than 1. The lower the value is, the
* better a mesh is optimized for post-transform vertex cache.
* Reported in @ref Units::RatioThousandths with a delay of 3
* frames. This value requires an active OpenGL context.
* @requires_gl46 Extension @gl_extension{ARB,pipeline_statistics_query}
*/
VertexFetchRatio = 1 << 3,
/**
* Ratio of primitives discarded by the clipping stage to count of
* primitives submitted. The ratio is 0 when all primitives pass
* the clipping stage and 1 when all are discarded. Can be used to
* measure efficiency of a frustum culling algorithm. Reported in
* @ref Units::PercentageThousandths with a delay of 3 frames. This
* value requires an active OpenGL context.
* @requires_gl46 Extension @gl_extension{ARB,pipeline_statistics_query}
*/
PrimitiveClipRatio = 1 << 4
#endif
};
/**
* @brief Measured values
*
* @see @ref FrameProfilerGL(Values, UnsignedInt), @ref setup()
*/
typedef Containers::EnumSet<Value> Values;
/**
* @brief Default constructor
*
* Call @ref setup() to populate the profiler with measurements.
*/
explicit FrameProfilerGL();
/**
* @brief Constructor
*
* Equivalent to default-constructing an instance and calling
* @ref setup() afterwards.
*/
explicit FrameProfilerGL(Values values, UnsignedInt maxFrameCount);
/** @brief Copying is not allowed */
FrameProfilerGL(const FrameProfilerGL&) = delete;
/** @brief Move constructor */
FrameProfilerGL(FrameProfilerGL&&) noexcept;
/** @brief Copying is not allowed */
FrameProfilerGL& operator=(const FrameProfilerGL&) = delete;
/** @brief Move assignment */
FrameProfilerGL& operator=(FrameProfilerGL&&) noexcept;
~FrameProfilerGL();
/**
* @brief Setup measured values
* @param values List of measuremed values
* @param maxFrameCount Max frame count over which to calculate a
* moving average. Expected to be at least @cpp 1 @ce.
*
* Calling @ref setup() on an already set up profiler will replace
* existing measurements with @p measurements and reset
* @ref measuredFrameCount() back to @cpp 0 @ce.
*/
void setup(Values values, UnsignedInt maxFrameCount);
/**
* @brief Measured values
*
* Corresponds to the @p values parameter passed to
* @ref FrameProfilerGL(Values, UnsignedInt) or @ref setup().
*/
Values values() const;
/**
* @brief Whether given measurement is available
*
* Returns @cpp true @ce if enough frames was captured to calculate
* given @p value, @cpp false @ce otherwise. Expects that @p value was
* enabled.
*/
bool isMeasurementAvailable(Value value) const;
using FrameProfiler::isMeasurementAvailable;
/**
* @brief Mean frame time in nanoseconds
*
* Expects that @ref Value::FrameTime was enabled, and that measurement
* data is available. See the flag documentation for more information.
* @see @ref isMeasurementAvailable(), @ref measurementMean()
*/
Double frameTimeMean() const;
/**
* @brief Mean CPU frame duration in nanoseconds
*
* Expects that @ref Value::CpuDuration was enabled, and that
* measurement data is available. See the flag documentation for more
* information.
* @see @ref isMeasurementAvailable(), @ref measurementMean()
*/
Double cpuDurationMean() const;
/**
* @brief Mean GPU frame duration in nanoseconds
*
* Expects that @ref Value::GpuDuration was enabled, and that
* measurement data is available. See the flag documentation for more
* information.
* @see @ref isMeasurementAvailable(), @ref measurementMean()
*/
Double gpuDurationMean() const;
#ifndef MAGNUM_TARGET_GLES
/**
* @brief Mean vertex fetch ratio in thousandths
*
* Expects that @ref Value::VertexFetchRatio was enabled, and that
* measurement data is available. See the flag documentation for more
* information.
* @requires_gl46 Extension @gl_extension{ARB,pipeline_statistics_query}
* @see @ref isMeasurementAvailable(), @ref measurementMean()
*/
Double vertexFetchRatioMean() const;
/**
* @brief Mean primitive clip ratio in percentage thousandths
*
* Expects that @ref Value::PrimitiveClipRatio was enabled, and that
* measurement data is available. See the flag documentation for more
* information.
* @requires_gl46 Extension @gl_extension{ARB,pipeline_statistics_query}
* @see @ref isMeasurementAvailable(), @ref measurementMean()
*/
Double primitiveClipRatioMean() const;
#endif
private:
using FrameProfiler::setup;
struct State;
Containers::Pointer<State> _state;
};
CORRADE_ENUMSET_OPERATORS(FrameProfilerGL::Values)
/**
@debugoperatorclassenum{FrameProfilerGL,FrameProfilerGL::Value}
@m_since{2020,06}
*/
MAGNUM_DEBUGTOOLS_EXPORT Debug& operator<<(Debug& debug, FrameProfilerGL::Value value);
/**
@debugoperatorclassenum{FrameProfilerGL,FrameProfilerGL::Values}
@m_since{2020,06}
*/
MAGNUM_DEBUGTOOLS_EXPORT Debug& operator<<(Debug& debug, FrameProfilerGL::Values value);
#ifdef MAGNUM_BUILD_DEPRECATED
/** @brief @copybrief FrameProfilerGL
* @m_deprecated_since_latest Use @ref FrameProfilerGL instead.
*/
typedef CORRADE_DEPRECATED("use FrameProfilerGL instead") FrameProfilerGL GLFrameProfiler;
#endif
#endif
}}
namespace Corrade { namespace Utility {
#ifdef MAGNUM_TARGET_GL
/**
@configurationvalue{Magnum::DebugTools::FrameProfilerGL::Value}
@m_since{2020,06}
*/
template<> struct MAGNUM_DEBUGTOOLS_EXPORT ConfigurationValue<Magnum::DebugTools::FrameProfilerGL::Value> {
ConfigurationValue() = delete;
/**
* @brief Writes enum value as a string
*
* If the value is invalid, returns an empty string. The returned view is
* always @relativeref{Corrade,Containers::StringViewFlag::NullTerminated}
* and @relativeref{Corrade,Containers::StringViewFlag::Global}.
*/
static Containers::StringView toString(Magnum::DebugTools::FrameProfilerGL::Value value, ConfigurationValueFlags);
/**
* @brief Reads enum value as a string
*
* If the string is invalid, returns a zero (invalid) value.
*/
static Magnum::DebugTools::FrameProfilerGL::Value fromString(Containers::StringView stringValue, ConfigurationValueFlags);
};
/**
@configurationvalue{Magnum::DebugTools::FrameProfilerGL::Values}
@m_since{2020,06}
*/
template<> struct MAGNUM_DEBUGTOOLS_EXPORT ConfigurationValue<Magnum::DebugTools::FrameProfilerGL::Values> {
ConfigurationValue() = delete;
/**
* @brief Writes enum set value as a string
*
* Writes the enum set as a sequence of flag names separated by spaces. If
* the value is invalid, returns an empty string.
*/
static Containers::String toString(Magnum::DebugTools::FrameProfilerGL::Values value, ConfigurationValueFlags);
/**
* @brief Reads enum set value as a string
*
* Assumes the string is a sequence of flag names separated by spaces. If
* the value is invalid, returns an empty set.
*/
static Magnum::DebugTools::FrameProfilerGL::Values fromString(Containers::StringView stringValue, ConfigurationValueFlags);
};
#endif
}}
#endif