mirror of
https://github.com/minetest/minetest.git
synced 2024-06-30 13:10:33 +02:00
Compare commits
7 Commits
91d984f299
...
b7f559698c
Author | SHA1 | Date | |
---|---|---|---|
|
b7f559698c | ||
|
9a1501ae89 | ||
|
be6c00d1b4 | ||
|
31337a0486 | ||
|
4dc3fd2fcc | ||
|
e41e2c43e8 | ||
|
7be7d15a02 |
@ -129,9 +129,9 @@ EM_BOOL CIrrDeviceSDL::MouseLeaveCallback(int eventType, const EmscriptenMouseEv
|
||||
}
|
||||
#endif
|
||||
|
||||
bool CIrrDeviceSDL::keyIsKnownSpecial(EKEY_CODE key)
|
||||
bool CIrrDeviceSDL::keyIsKnownSpecial(EKEY_CODE irrlichtKey)
|
||||
{
|
||||
switch (key) {
|
||||
switch (irrlichtKey) {
|
||||
// keys which are known to have safe special character interpretation
|
||||
// could need changes over time (removals and additions!)
|
||||
case KEY_RETURN:
|
||||
@ -189,24 +189,68 @@ bool CIrrDeviceSDL::keyIsKnownSpecial(EKEY_CODE key)
|
||||
}
|
||||
}
|
||||
|
||||
int CIrrDeviceSDL::findCharToPassToIrrlicht(int assumedChar, EKEY_CODE key)
|
||||
int CIrrDeviceSDL::findCharToPassToIrrlicht(uint32_t sdlKey, EKEY_CODE irrlichtKey, bool numlock)
|
||||
{
|
||||
switch (irrlichtKey) {
|
||||
// special cases that always return a char regardless of how the SDL keycode
|
||||
// looks
|
||||
switch (key) {
|
||||
case KEY_RETURN:
|
||||
case KEY_ESCAPE:
|
||||
return (int)key;
|
||||
return (int)irrlichtKey;
|
||||
|
||||
// This is necessary for keys on the numpad because they don't use the same
|
||||
// keycodes as their non-numpad versions (whose keycodes correspond to chars),
|
||||
// but have their own SDL keycodes and their own Irrlicht keycodes (which
|
||||
// don't correspond to chars).
|
||||
case KEY_MULTIPLY:
|
||||
return '*';
|
||||
case KEY_ADD:
|
||||
return '+';
|
||||
case KEY_SUBTRACT:
|
||||
return '-';
|
||||
case KEY_DIVIDE:
|
||||
return '/';
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (numlock) {
|
||||
// Number keys on the numpad are also affected, but we only want them
|
||||
// to produce number chars when numlock is enabled.
|
||||
switch (irrlichtKey) {
|
||||
case KEY_NUMPAD0:
|
||||
return '0';
|
||||
case KEY_NUMPAD1:
|
||||
return '1';
|
||||
case KEY_NUMPAD2:
|
||||
return '2';
|
||||
case KEY_NUMPAD3:
|
||||
return '3';
|
||||
case KEY_NUMPAD4:
|
||||
return '4';
|
||||
case KEY_NUMPAD5:
|
||||
return '5';
|
||||
case KEY_NUMPAD6:
|
||||
return '6';
|
||||
case KEY_NUMPAD7:
|
||||
return '7';
|
||||
case KEY_NUMPAD8:
|
||||
return '8';
|
||||
case KEY_NUMPAD9:
|
||||
return '9';
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// SDL in-place ORs values with no character representation with 1<<30
|
||||
// https://wiki.libsdl.org/SDL2/SDLKeycodeLookup
|
||||
if (assumedChar & (1 << 30))
|
||||
// This also affects the numpad keys btw.
|
||||
if (sdlKey & (1 << 30))
|
||||
return 0;
|
||||
|
||||
switch (key) {
|
||||
switch (irrlichtKey) {
|
||||
case KEY_PRIOR:
|
||||
case KEY_NEXT:
|
||||
case KEY_HOME:
|
||||
@ -218,7 +262,7 @@ int CIrrDeviceSDL::findCharToPassToIrrlicht(int assumedChar, EKEY_CODE key)
|
||||
case KEY_NUMLOCK:
|
||||
return 0;
|
||||
default:
|
||||
return assumedChar;
|
||||
return sdlKey;
|
||||
}
|
||||
}
|
||||
|
||||
@ -825,7 +869,8 @@ bool CIrrDeviceSDL::run()
|
||||
irrevent.KeyInput.PressedDown = (SDL_event.type == SDL_KEYDOWN);
|
||||
irrevent.KeyInput.Shift = (SDL_event.key.keysym.mod & KMOD_SHIFT) != 0;
|
||||
irrevent.KeyInput.Control = (SDL_event.key.keysym.mod & KMOD_CTRL) != 0;
|
||||
irrevent.KeyInput.Char = findCharToPassToIrrlicht(mp.SDLKey, key);
|
||||
irrevent.KeyInput.Char = findCharToPassToIrrlicht(mp.SDLKey, key,
|
||||
(SDL_event.key.keysym.mod & KMOD_NUM) != 0);
|
||||
postEventFromUser(irrevent);
|
||||
} break;
|
||||
|
||||
|
@ -273,10 +273,10 @@ class CIrrDeviceSDL : public CIrrDeviceStub
|
||||
|
||||
#endif
|
||||
// Check if a key is a known special character with no side effects on text boxes.
|
||||
static bool keyIsKnownSpecial(EKEY_CODE key);
|
||||
static bool keyIsKnownSpecial(EKEY_CODE irrlichtKey);
|
||||
|
||||
// Return the Char that should be sent to Irrlicht for the given key (either the one passed in or 0).
|
||||
static int findCharToPassToIrrlicht(int assumedChar, EKEY_CODE key);
|
||||
static int findCharToPassToIrrlicht(uint32_t sdlKey, EKEY_CODE irrlichtKey, bool numlock);
|
||||
|
||||
// Check if a text box is in focus. Enable or disable SDL_TEXTINPUT events only if in focus.
|
||||
void resetReceiveTextInputEvents();
|
||||
|
@ -26,15 +26,28 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include <IVideoDriver.h>
|
||||
#include "profiler.h"
|
||||
|
||||
/* Profiler display */
|
||||
|
||||
/** \brief Draws graph every frame using data given by Profiler.
|
||||
|
||||
It displays only entries that are recorded for profiler graph (via Profiler::graphAdd,
|
||||
ScopeProfilerType::SPT_GRAPH_ADD and other) and Profiler itself doesn't show them.
|
||||
|
||||
Each profiling entry described with upper bound value, entry name and lower bound
|
||||
value on its right. Graph is displayed as \e line if it is relative (lower value
|
||||
is not 0) and \e filled if it is absolute.
|
||||
|
||||
\ingroup Profiling
|
||||
*/
|
||||
class ProfilerGraph
|
||||
{
|
||||
private:
|
||||
/// One-frame slice of graph values.
|
||||
struct Piece
|
||||
{
|
||||
Piece(Profiler::GraphValues v) : values(std::move(v)) {}
|
||||
Profiler::GraphValues values;
|
||||
};
|
||||
/// Data for drawing one graph. Updates every frame.
|
||||
struct Meta
|
||||
{
|
||||
float min;
|
||||
@ -54,6 +67,8 @@ class ProfilerGraph
|
||||
|
||||
ProfilerGraph() = default;
|
||||
|
||||
/// Adds graph values to the end of graph (rendered at right side) and
|
||||
/// removes the oldest ones (beyond the `m_log_max_size`).
|
||||
void put(const Profiler::GraphValues &values);
|
||||
|
||||
void draw(s32 x_left, s32 y_bottom, video::IVideoDriver *driver,
|
||||
|
137
src/profiler.h
137
src/profiler.h
@ -29,22 +29,63 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "util/timetaker.h"
|
||||
#include "util/numeric.h" // paging()
|
||||
|
||||
// Global profiler
|
||||
class Profiler;
|
||||
extern Profiler *g_profiler;
|
||||
|
||||
/*
|
||||
Time profiler
|
||||
/** \defgroup Profiling Profiling tools
|
||||
\brief Embedded tools to profile CPU time or anything else that is recorded
|
||||
by certain functions.
|
||||
|
||||
An example with global profiler (#g_profiler), that is available in any file
|
||||
with profiler.h included:
|
||||
\code{.c++}
|
||||
void functionToProfie(int count) {
|
||||
// Record (add) time till function (scope) end
|
||||
ScopeProfiler scope_profiler(g_profiler, "functionToProfie()"); // SPT_ADD by default
|
||||
// Record (add) `count`
|
||||
g_profiler->add("functionToProfie() count", count)
|
||||
}
|
||||
\endcode
|
||||
In this example "add" method is used, so if function is called several times during
|
||||
g_profiler cycle, sum of all recorded values will be shown at cycle end. See
|
||||
#g_profiler for details about cycle and info showing.
|
||||
|
||||
TimeTaker can be used instead of ScopeProfiler.
|
||||
\{
|
||||
*/
|
||||
|
||||
|
||||
/** \brief Collects values (time intervals, counts and other) in named entries.
|
||||
|
||||
Can be used to get sum, average or maximum of recorded values for each entry. Gives
|
||||
result in text form via print().
|
||||
|
||||
Can collect values for #ProfilerGraph and give them via graphPop().
|
||||
|
||||
For usage, see \ref Profiling.
|
||||
*/
|
||||
class Profiler
|
||||
{
|
||||
public:
|
||||
Profiler();
|
||||
|
||||
/** \brief Records the \p value in entry with given \p name to get sum of recorded values.
|
||||
\param[in] name: entry name; can be same for several function calls
|
||||
\param[in] value: value to record
|
||||
*/
|
||||
void add(const std::string &name, float value);
|
||||
|
||||
/** \brief Records the \p value in entry with given \p name to get average of recorded values.
|
||||
\param[in] name: entry name; can be same for several function calls
|
||||
\param[in] value: value to record
|
||||
*/
|
||||
void avg(const std::string &name, float value);
|
||||
|
||||
/** \brief Records the \p value in entry with given \p name to get maximum of recorded values.
|
||||
\param[in] name: entry name; can be same for several function calls
|
||||
\param[in] value: value to record
|
||||
*/
|
||||
void max(const std::string &name, float value);
|
||||
|
||||
/// Clears all profiling entries (#m_data). Does not affect #m_graphvalues.
|
||||
void clear();
|
||||
|
||||
float getValue(const std::string &name) const;
|
||||
@ -53,16 +94,46 @@ class Profiler
|
||||
|
||||
typedef std::map<std::string, float> GraphValues;
|
||||
|
||||
// Returns the line count
|
||||
/** \brief Prints collected data formatted as table.
|
||||
|
||||
Prints each entry as one line which contains name, avgCount and value.
|
||||
Meaning of printed numbers depends on used recording method (add/avg/max).
|
||||
avgCount makes sense only for "avg" method and shows number of records;
|
||||
always shows 1 for other methods.
|
||||
|
||||
Breaks all entries into \p pagecount pages and print only given \p page.
|
||||
|
||||
\param[out] o: stream to print into
|
||||
\param[in] page: number of page to print
|
||||
\param[in] pagecount: count of pages to break data into
|
||||
\returns printed line count
|
||||
*/
|
||||
int print(std::ostream &o, u32 page = 1, u32 pagecount = 1);
|
||||
|
||||
/** \brief Breaks #m_data (entries) into \p pagecount pages (GraphValues) and
|
||||
writes values on given \p page into \p o.
|
||||
\param[out] o: variable to write page into
|
||||
\param[in] page: page to get
|
||||
\param[in] pagecount: number of page to break data into
|
||||
*/
|
||||
void getPage(GraphValues &o, u32 page, u32 pagecount);
|
||||
|
||||
|
||||
/** \brief Records the \p value in graph entry with given \p id (name) to get
|
||||
exactly this value.
|
||||
\param[in] id: entry name
|
||||
\param[in] value: value to record
|
||||
*/
|
||||
void graphSet(const std::string &id, float value)
|
||||
{
|
||||
MutexAutoLock lock(m_mutex);
|
||||
m_graphvalues[id] = value;
|
||||
}
|
||||
|
||||
/** \brief Records the \p value in graph entry with given \p id (name) to get
|
||||
sum of recorded values.
|
||||
\param[in] id: entry name
|
||||
\param[in] value: value to record
|
||||
*/
|
||||
void graphAdd(const std::string &id, float value)
|
||||
{
|
||||
MutexAutoLock lock(m_mutex);
|
||||
@ -72,6 +143,9 @@ class Profiler
|
||||
else
|
||||
it->second += value;
|
||||
}
|
||||
|
||||
/// \brief Gives m_graphvalues into \p result.
|
||||
/// \param[out] result: Variable to record values into
|
||||
void graphPop(GraphValues &result)
|
||||
{
|
||||
MutexAutoLock lock(m_mutex);
|
||||
@ -79,6 +153,8 @@ class Profiler
|
||||
std::swap(result, m_graphvalues);
|
||||
}
|
||||
|
||||
/// \brief Removes entry with given \p name.
|
||||
/// \param[in] name: Name of entry to remove
|
||||
void remove(const std::string& name)
|
||||
{
|
||||
MutexAutoLock lock(m_mutex);
|
||||
@ -87,7 +163,10 @@ class Profiler
|
||||
|
||||
private:
|
||||
struct DataPair {
|
||||
/// Recorded value. Recording method depends on used functions (add/avg/max)
|
||||
/// of profiler.
|
||||
float value = 0;
|
||||
/// Count of records if "avg" method is used.
|
||||
int avgcount = 0;
|
||||
|
||||
inline void reset() {
|
||||
@ -102,33 +181,69 @@ class Profiler
|
||||
};
|
||||
|
||||
std::mutex m_mutex;
|
||||
/// All the profiler entries, stored until `clear()` call.
|
||||
std::map<std::string, DataPair> m_data;
|
||||
/// Values for profiler graph collected until next frame draw. Value history
|
||||
/// is stored in `ProfilerGraph`.
|
||||
std::map<std::string, float> m_graphvalues;
|
||||
u64 m_start_time;
|
||||
};
|
||||
|
||||
|
||||
/** \brief Global profiler. User can view its data via in-game profiler menu,
|
||||
graph or "/profiler" command.
|
||||
|
||||
Profiling cycles are managed in Game class:
|
||||
|
||||
- cycle for profiler menu (GameUI::updateProfiler()) is managed in
|
||||
Game::updateProfilers() and lasts for \c profiler_print_interval seconds (user
|
||||
setting) or for 3 seconds if setting is set to 0;
|
||||
|
||||
- cycle for ProfilerGraph is managed in Game::updateProfilerGraphs() and lasts
|
||||
for one frame;
|
||||
*/
|
||||
extern Profiler* g_profiler;
|
||||
|
||||
|
||||
enum ScopeProfilerType : u8
|
||||
{
|
||||
/// Record time with Profiler::add() (to get sum of recorded values) at scope end.
|
||||
SPT_ADD = 1,
|
||||
/// Record time with Profiler::avg() (to get average of recorded values) at scope end.
|
||||
SPT_AVG,
|
||||
/// Record time with Profiler::graphAdd() (to get sum of recorded values on
|
||||
/// ProfilerGraph) at scope end.
|
||||
SPT_GRAPH_ADD,
|
||||
/// Record time with Profiler::max() (to get maximum of recorded values) at scope end.
|
||||
SPT_MAX
|
||||
};
|
||||
|
||||
// Note: this class should be kept lightweight.
|
||||
|
||||
/** \brief A class for time measurements. Each created object records time from its
|
||||
construction till scope end.
|
||||
|
||||
Note: this class should be kept lightweight.
|
||||
*/
|
||||
class ScopeProfiler
|
||||
{
|
||||
public:
|
||||
/** \brief Begins measurement until scope end.Result will be recorded to
|
||||
\p name
|
||||
profiling entry in \p profiler (profiling entries are created/deleted automatically).
|
||||
*/
|
||||
ScopeProfiler(Profiler *profiler, const std::string &name,
|
||||
ScopeProfilerType type = SPT_ADD,
|
||||
TimePrecision precision = PRECISION_MILLI);
|
||||
|
||||
/// Ends measurement and record result in profiler.
|
||||
~ScopeProfiler();
|
||||
|
||||
private:
|
||||
Profiler *m_profiler = nullptr;
|
||||
std::string m_name;
|
||||
u64 m_time1;
|
||||
Profiler *m_profiler = nullptr; /// Profiler to record in
|
||||
std::string m_name; /// Name of profiler entry to record in
|
||||
u64 m_time1; /// Record start time
|
||||
ScopeProfilerType m_type;
|
||||
TimePrecision m_precision;
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
Loading…
Reference in New Issue
Block a user