mirror of
https://github.com/minetest/minetest.git
synced 2024-07-02 14: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
|
#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
|
// keys which are known to have safe special character interpretation
|
||||||
// could need changes over time (removals and additions!)
|
// could need changes over time (removals and additions!)
|
||||||
case KEY_RETURN:
|
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
|
// special cases that always return a char regardless of how the SDL keycode
|
||||||
// looks
|
// looks
|
||||||
switch (key) {
|
|
||||||
case KEY_RETURN:
|
case KEY_RETURN:
|
||||||
case KEY_ESCAPE:
|
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:
|
default:
|
||||||
break;
|
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
|
// SDL in-place ORs values with no character representation with 1<<30
|
||||||
// https://wiki.libsdl.org/SDL2/SDLKeycodeLookup
|
// https://wiki.libsdl.org/SDL2/SDLKeycodeLookup
|
||||||
if (assumedChar & (1 << 30))
|
// This also affects the numpad keys btw.
|
||||||
|
if (sdlKey & (1 << 30))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
switch (key) {
|
switch (irrlichtKey) {
|
||||||
case KEY_PRIOR:
|
case KEY_PRIOR:
|
||||||
case KEY_NEXT:
|
case KEY_NEXT:
|
||||||
case KEY_HOME:
|
case KEY_HOME:
|
||||||
@ -218,7 +262,7 @@ int CIrrDeviceSDL::findCharToPassToIrrlicht(int assumedChar, EKEY_CODE key)
|
|||||||
case KEY_NUMLOCK:
|
case KEY_NUMLOCK:
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
return assumedChar;
|
return sdlKey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -825,7 +869,8 @@ bool CIrrDeviceSDL::run()
|
|||||||
irrevent.KeyInput.PressedDown = (SDL_event.type == SDL_KEYDOWN);
|
irrevent.KeyInput.PressedDown = (SDL_event.type == SDL_KEYDOWN);
|
||||||
irrevent.KeyInput.Shift = (SDL_event.key.keysym.mod & KMOD_SHIFT) != 0;
|
irrevent.KeyInput.Shift = (SDL_event.key.keysym.mod & KMOD_SHIFT) != 0;
|
||||||
irrevent.KeyInput.Control = (SDL_event.key.keysym.mod & KMOD_CTRL) != 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);
|
postEventFromUser(irrevent);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -273,10 +273,10 @@ class CIrrDeviceSDL : public CIrrDeviceStub
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
// Check if a key is a known special character with no side effects on text boxes.
|
// 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).
|
// 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.
|
// Check if a text box is in focus. Enable or disable SDL_TEXTINPUT events only if in focus.
|
||||||
void resetReceiveTextInputEvents();
|
void resetReceiveTextInputEvents();
|
||||||
|
@ -26,15 +26,28 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <IVideoDriver.h>
|
#include <IVideoDriver.h>
|
||||||
#include "profiler.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
|
class ProfilerGraph
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
/// One-frame slice of graph values.
|
||||||
struct Piece
|
struct Piece
|
||||||
{
|
{
|
||||||
Piece(Profiler::GraphValues v) : values(std::move(v)) {}
|
Piece(Profiler::GraphValues v) : values(std::move(v)) {}
|
||||||
Profiler::GraphValues values;
|
Profiler::GraphValues values;
|
||||||
};
|
};
|
||||||
|
/// Data for drawing one graph. Updates every frame.
|
||||||
struct Meta
|
struct Meta
|
||||||
{
|
{
|
||||||
float min;
|
float min;
|
||||||
@ -54,6 +67,8 @@ class ProfilerGraph
|
|||||||
|
|
||||||
ProfilerGraph() = default;
|
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 put(const Profiler::GraphValues &values);
|
||||||
|
|
||||||
void draw(s32 x_left, s32 y_bottom, video::IVideoDriver *driver,
|
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/timetaker.h"
|
||||||
#include "util/numeric.h" // paging()
|
#include "util/numeric.h" // paging()
|
||||||
|
|
||||||
// Global profiler
|
|
||||||
class Profiler;
|
|
||||||
extern Profiler *g_profiler;
|
|
||||||
|
|
||||||
/*
|
/** \defgroup Profiling Profiling tools
|
||||||
Time profiler
|
\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
|
class Profiler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Profiler();
|
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);
|
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);
|
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);
|
void max(const std::string &name, float value);
|
||||||
|
|
||||||
|
/// Clears all profiling entries (#m_data). Does not affect #m_graphvalues.
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
float getValue(const std::string &name) const;
|
float getValue(const std::string &name) const;
|
||||||
@ -53,16 +94,46 @@ class Profiler
|
|||||||
|
|
||||||
typedef std::map<std::string, float> GraphValues;
|
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);
|
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);
|
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)
|
void graphSet(const std::string &id, float value)
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
m_graphvalues[id] = value;
|
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)
|
void graphAdd(const std::string &id, float value)
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
@ -72,6 +143,9 @@ class Profiler
|
|||||||
else
|
else
|
||||||
it->second += value;
|
it->second += value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Gives m_graphvalues into \p result.
|
||||||
|
/// \param[out] result: Variable to record values into
|
||||||
void graphPop(GraphValues &result)
|
void graphPop(GraphValues &result)
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
@ -79,6 +153,8 @@ class Profiler
|
|||||||
std::swap(result, m_graphvalues);
|
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)
|
void remove(const std::string& name)
|
||||||
{
|
{
|
||||||
MutexAutoLock lock(m_mutex);
|
MutexAutoLock lock(m_mutex);
|
||||||
@ -87,7 +163,10 @@ class Profiler
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
struct DataPair {
|
struct DataPair {
|
||||||
|
/// Recorded value. Recording method depends on used functions (add/avg/max)
|
||||||
|
/// of profiler.
|
||||||
float value = 0;
|
float value = 0;
|
||||||
|
/// Count of records if "avg" method is used.
|
||||||
int avgcount = 0;
|
int avgcount = 0;
|
||||||
|
|
||||||
inline void reset() {
|
inline void reset() {
|
||||||
@ -102,33 +181,69 @@ class Profiler
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::mutex m_mutex;
|
std::mutex m_mutex;
|
||||||
|
/// All the profiler entries, stored until `clear()` call.
|
||||||
std::map<std::string, DataPair> m_data;
|
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;
|
std::map<std::string, float> m_graphvalues;
|
||||||
u64 m_start_time;
|
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
|
enum ScopeProfilerType : u8
|
||||||
{
|
{
|
||||||
|
/// Record time with Profiler::add() (to get sum of recorded values) at scope end.
|
||||||
SPT_ADD = 1,
|
SPT_ADD = 1,
|
||||||
|
/// Record time with Profiler::avg() (to get average of recorded values) at scope end.
|
||||||
SPT_AVG,
|
SPT_AVG,
|
||||||
|
/// Record time with Profiler::graphAdd() (to get sum of recorded values on
|
||||||
|
/// ProfilerGraph) at scope end.
|
||||||
SPT_GRAPH_ADD,
|
SPT_GRAPH_ADD,
|
||||||
|
/// Record time with Profiler::max() (to get maximum of recorded values) at scope end.
|
||||||
SPT_MAX
|
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
|
class ScopeProfiler
|
||||||
{
|
{
|
||||||
public:
|
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,
|
ScopeProfiler(Profiler *profiler, const std::string &name,
|
||||||
ScopeProfilerType type = SPT_ADD,
|
ScopeProfilerType type = SPT_ADD,
|
||||||
TimePrecision precision = PRECISION_MILLI);
|
TimePrecision precision = PRECISION_MILLI);
|
||||||
|
|
||||||
|
/// Ends measurement and record result in profiler.
|
||||||
~ScopeProfiler();
|
~ScopeProfiler();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Profiler *m_profiler = nullptr;
|
Profiler *m_profiler = nullptr; /// Profiler to record in
|
||||||
std::string m_name;
|
std::string m_name; /// Name of profiler entry to record in
|
||||||
u64 m_time1;
|
u64 m_time1; /// Record start time
|
||||||
ScopeProfilerType m_type;
|
ScopeProfilerType m_type;
|
||||||
TimePrecision m_precision;
|
TimePrecision m_precision;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
Loading…
Reference in New Issue
Block a user