Merge branch 'minetest:master' into Cinematic_Camera_Key

This commit is contained in:
DragonWrangler1 2024-09-17 09:48:01 -07:00 committed by GitHub
commit dbb6c0453e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 499 additions and 157 deletions

View File

@ -56,6 +56,11 @@ if((WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR APPLE)
endif()
set(ENABLE_LTO ${DEFAULT_ENABLE_LTO} CACHE BOOL "Use Link Time Optimization")
set(BUILD_WITH_TRACY FALSE CACHE BOOL
"Fetch and build with the Tracy profiler client")
set(FETCH_TRACY_GIT_TAG "master" CACHE STRING
"Git tag for fetching Tracy client. Match with your server (gui) version")
set(DEFAULT_RUN_IN_PLACE FALSE)
if(WIN32)
set(DEFAULT_RUN_IN_PLACE TRUE)
@ -370,3 +375,19 @@ if(BUILD_DOCUMENTATION)
)
endif()
endif()
# Fetch Tracy
if(BUILD_WITH_TRACY)
include(FetchContent)
message(STATUS "Fetching Tracy (${FETCH_TRACY_GIT_TAG})...")
FetchContent_Declare(
tracy
GIT_REPOSITORY https://github.com/wolfpld/tracy.git
GIT_TAG ${FETCH_TRACY_GIT_TAG}
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
)
FetchContent_MakeAvailable(tracy)
message(STATUS "Fetching Tracy - done")
endif()

View File

@ -11,7 +11,6 @@ attribute vec2 inTexCoord0;
uniform mat4 uWVPMatrix;
uniform mat4 uWVMatrix;
uniform mat4 uNMatrix;
uniform mat4 uTMatrix0;
uniform float uThickness;

View File

@ -40,6 +40,8 @@ General options and their default values:
ENABLE_UPDATE_CHECKER=TRUE - Whether to enable update checks by default
INSTALL_DEVTEST=FALSE - Whether the Development Test game should be installed alongside Minetest
USE_GPROF=FALSE - Enable profiling using GProf
BUILD_WITH_TRACY=FALSE - Fetch and build with the Tracy profiler client
FETCH_TRACY_GIT_TAG=master - Git tag for fetching Tracy client. Match with your server (gui) version
VERSION_EXTRA= - Text to append to version (e.g. VERSION_EXTRA=foobar -> Minetest 0.4.9-foobar)
Library specific options:

View File

@ -1,6 +1,6 @@
# Miscellaneous
## Profiling Minetest on Linux
## Profiling Minetest on Linux with perf
We will be using a tool called "perf", which you can get by installing `perf` or `linux-perf` or `linux-tools-common`.
@ -36,3 +36,54 @@ Give both files to the developer and also provide:
* commit the source was built from and/or modified source code (if applicable)
Hotspot will resolve symbols correctly when pointing the sysroot option at the collected libs.
## Profiling with Tracy
[Tracy](https://github.com/wolfpld/tracy) is
> A real time, nanosecond resolution, remote telemetry, hybrid frame and sampling
> profiler for games and other applications.
It allows one to annotate important functions and generate traces, where one can
see when each individual function call happened, and how long it took.
Tracy can also record when frames, e.g. server step, start and end, and inspect
frames that took longer than usual. Minetest already contains annotations for
its frames.
See also [Tracy's official documentation](https://github.com/wolfpld/tracy/releases/latest/download/tracy.pdf).
### Installing
Tracy consists of a client (Minetest) and a server (the gui).
Install the server, e.g. using your package manager.
### Building
Build Minetest with `-DDBUILD_WITH_TRACY=1`, this will fetch Tracy for building
the Tracy client. And use `FETCH_TRACY_GIT_TAG` to get a version matching your
Tracy server, e.g. `-DFETCH_TRACY_GIT_TAG=v0.11.0` if it's `0.11.0`.
To actually use Tracy, you also have to enable it with Tracy's build options:
```
-DTRACY_ENABLE=1 -DTRACY_ONLY_LOCALHOST=1
```
See Tracy's documentation for more build options.
### Using in C++
Start the Tracy server and Minetest. You should see Minetest in the menu.
To actually get useful traces, you have to annotate functions with `ZoneScoped`
macros and recompile. Please refer to Tracy's official documentation.
### Using in Lua
Tracy also supports Lua.
If built with Tracy, Minetest loads its API in the global `tracy` table.
See Tracy's official documentation for more information.
Note: The whole Tracy Lua API is accessible to all mods. And we don't check if it
is or becomes insecure. Run untrusted mods at your own risk.

View File

@ -11394,6 +11394,16 @@ Functions: bit.tobit, bit.tohex, bit.bnot, bit.band, bit.bor, bit.bxor, bit.lshi
See http://bitop.luajit.org/ for advanced information.
Tracy Profiler
--------------
Minetest can be built with support for the Tracy profiler, which can also be
useful for profiling mods and is exposed to Lua as the global `tracy`.
See doc/developing/misc.md for details.
Note: This is a development feature and not covered by compatibility promises.
Error Handling
--------------

View File

@ -7,6 +7,13 @@
#include <vector>
#include "IIndexBuffer.h"
// Define to receive warnings when violating the hw mapping hints
//#define INDEXBUFFER_HINT_DEBUG
#ifdef INDEXBUFFER_HINT_DEBUG
#include "../src/os.h"
#endif
namespace irr
{
namespace scene
@ -58,6 +65,13 @@ public:
void setDirty() override
{
++ChangedID;
#ifdef INDEXBUFFER_HINT_DEBUG
if (MappingHint == EHM_STATIC && HWBuffer) {
char buf[100];
snprintf_irr(buf, sizeof(buf), "CIndexBuffer @ %p modified, but it has a static hint", this);
os::Printer::log(buf, ELL_WARNING);
}
#endif
}
u32 getChangedID() const override { return ChangedID; }

View File

@ -7,6 +7,13 @@
#include <vector>
#include "IVertexBuffer.h"
// Define to receive warnings when violating the hw mapping hints
//#define VERTEXBUFFER_HINT_DEBUG
#ifdef VERTEXBUFFER_HINT_DEBUG
#include "../src/os.h"
#endif
namespace irr
{
namespace scene
@ -87,6 +94,13 @@ public:
void setDirty() override
{
++ChangedID;
#ifdef VERTEXBUFFER_HINT_DEBUG
if (MappingHint == EHM_STATIC && HWBuffer) {
char buf[100];
snprintf_irr(buf, sizeof(buf), "CVertexBuffer @ %p modified, but it has a static hint", this);
os::Printer::log(buf, ELL_WARNING);
}
#endif
}
u32 getChangedID() const override { return ChangedID; }

View File

@ -42,7 +42,7 @@ class IReferenceCounted
public:
//! Constructor.
IReferenceCounted() :
DebugName(0), ReferenceCounter(1)
ReferenceCounter(1)
{
}
@ -136,6 +136,7 @@ public:
return ReferenceCounter;
}
#ifdef _DEBUG
//! Returns the debug name of the object.
/** The Debugname may only be set and changed by the object
itself. This method should only be used in Debug mode.
@ -157,7 +158,10 @@ protected:
private:
//! The debug name.
const c8 *DebugName;
const c8 *DebugName = nullptr;
#endif
private:
//! The reference counter. Mutable to do reference counting on const objects.
mutable s32 ReferenceCounter;

View File

@ -468,6 +468,10 @@ foreach(object_lib
target_include_directories(${object_lib} PRIVATE ${link_includes})
# Add objects from object library to main library
target_sources(IrrlichtMt PRIVATE $<TARGET_OBJECTS:${object_lib}>)
if(BUILD_WITH_TRACY)
target_link_libraries(${object_lib} PRIVATE Tracy::TracyClient)
endif()
endforeach()
# Alias target provides add_submodule compatibility
@ -506,6 +510,9 @@ target_link_libraries(IrrlichtMt PRIVATE
if(WIN32)
target_compile_definitions(IrrlichtMt INTERFACE _IRR_WINDOWS_API_) # used in _IRR_DEBUG_BREAK_IF definition in a public header
endif()
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_definitions(IrrlichtMt INTERFACE _DEBUG) # same
endif()
if(APPLE OR ANDROID OR EMSCRIPTEN)
target_compile_definitions(IrrlichtMt PUBLIC IRR_MOBILE_PATHS)
endif()

View File

@ -4,6 +4,7 @@
// For conditions of distribution and use, see copyright notice in Irrlicht.h
#include "FixedPipelineRenderer.h"
#include "os.h"
#include "IVideoDriver.h"
@ -15,23 +16,20 @@ namespace video
// Base callback
COpenGL3MaterialBaseCB::COpenGL3MaterialBaseCB() :
FirstUpdateBase(true), WVPMatrixID(-1), WVMatrixID(-1), NMatrixID(-1),
FirstUpdateBase(true), WVPMatrixID(-1), WVMatrixID(-1),
FogEnableID(-1), FogTypeID(-1), FogColorID(-1), FogStartID(-1),
FogEndID(-1), FogDensityID(-1), ThicknessID(-1), LightEnable(false), MaterialAmbient(SColorf(0.f, 0.f, 0.f)), MaterialDiffuse(SColorf(0.f, 0.f, 0.f)), MaterialEmissive(SColorf(0.f, 0.f, 0.f)), MaterialSpecular(SColorf(0.f, 0.f, 0.f)),
MaterialShininess(0.f), FogEnable(0), FogType(1), FogColor(SColorf(0.f, 0.f, 0.f, 1.f)), FogStart(0.f), FogEnd(0.f), FogDensity(0.f), Thickness(1.f)
FogEndID(-1), FogDensityID(-1), ThicknessID(-1), Thickness(1.f), FogEnable(false)
{
}
void COpenGL3MaterialBaseCB::OnSetMaterial(const SMaterial &material)
{
LightEnable = material.Lighting;
MaterialAmbient = SColorf(material.AmbientColor);
MaterialDiffuse = SColorf(material.DiffuseColor);
MaterialEmissive = SColorf(material.EmissiveColor);
MaterialSpecular = SColorf(material.SpecularColor);
MaterialShininess = material.Shininess;
#ifdef _DEBUG
if (material.Lighting)
os::Printer::log("Lighted material not supported in unified driver.", ELL_INFORMATION);
#endif
FogEnable = material.FogEnable ? 1 : 0;
FogEnable = material.FogEnable;
Thickness = (material.Thickness > 0.f) ? material.Thickness : 1.f;
}
@ -43,7 +41,6 @@ void COpenGL3MaterialBaseCB::OnSetConstants(IMaterialRendererServices *services,
if (FirstUpdateBase) {
WVPMatrixID = services->getVertexShaderConstantID("uWVPMatrix");
WVMatrixID = services->getVertexShaderConstantID("uWVMatrix");
NMatrixID = services->getVertexShaderConstantID("uNMatrix");
FogEnableID = services->getVertexShaderConstantID("uFogEnable");
FogTypeID = services->getVertexShaderConstantID("uFogType");
@ -56,31 +53,29 @@ void COpenGL3MaterialBaseCB::OnSetConstants(IMaterialRendererServices *services,
FirstUpdateBase = false;
}
const core::matrix4 W = driver->getTransform(ETS_WORLD);
const core::matrix4 V = driver->getTransform(ETS_VIEW);
const core::matrix4 P = driver->getTransform(ETS_PROJECTION);
const core::matrix4 &W = driver->getTransform(ETS_WORLD);
const core::matrix4 &V = driver->getTransform(ETS_VIEW);
const core::matrix4 &P = driver->getTransform(ETS_PROJECTION);
core::matrix4 Matrix = P * V * W;
services->setPixelShaderConstant(WVPMatrixID, Matrix.pointer(), 16);
Matrix = V * W;
core::matrix4 Matrix = V * W;
services->setPixelShaderConstant(WVMatrixID, Matrix.pointer(), 16);
Matrix.makeInverse();
services->setPixelShaderConstant(NMatrixID, Matrix.getTransposed().pointer(), 16);
Matrix = P * Matrix;
services->setPixelShaderConstant(WVPMatrixID, Matrix.pointer(), 16);
services->setPixelShaderConstant(FogEnableID, &FogEnable, 1);
s32 TempEnable = FogEnable ? 1 : 0;
services->setPixelShaderConstant(FogEnableID, &TempEnable, 1);
if (FogEnable) {
SColor TempColor(0);
E_FOG_TYPE TempType = EFT_FOG_LINEAR;
bool TempPerFragment = false;
bool TempRange = false;
f32 FogStart, FogEnd, FogDensity;
bool unused = false;
driver->getFog(TempColor, TempType, FogStart, FogEnd, FogDensity, TempPerFragment, TempRange);
driver->getFog(TempColor, TempType, FogStart, FogEnd, FogDensity, unused, unused);
FogType = (s32)TempType;
FogColor = SColorf(TempColor);
s32 FogType = (s32)TempType;
SColorf FogColor(TempColor);
services->setPixelShaderConstant(FogTypeID, &FogType, 1);
services->setPixelShaderConstant(FogColorID, reinterpret_cast<f32 *>(&FogColor), 4);

View File

@ -26,7 +26,6 @@ protected:
s32 WVPMatrixID;
s32 WVMatrixID;
s32 NMatrixID;
s32 FogEnableID;
s32 FogTypeID;
@ -37,22 +36,8 @@ protected:
s32 ThicknessID;
bool LightEnable;
SColorf GlobalAmbient;
SColorf MaterialAmbient;
SColorf MaterialDiffuse;
SColorf MaterialEmissive;
SColorf MaterialSpecular;
f32 MaterialShininess;
s32 FogEnable;
s32 FogType;
SColorf FogColor;
f32 FogStart;
f32 FogEnd;
f32 FogDensity;
f32 Thickness;
bool FogEnable;
};
class COpenGL3MaterialSolidCB : public COpenGL3MaterialBaseCB

View File

@ -52,7 +52,6 @@ public:
// prints out a string to the console out stdout or debug log or whatever
static void print(const c8 *message, ELOG_LEVEL ll = ELL_INFORMATION);
static void log(const c8 *message, ELOG_LEVEL ll = ELL_INFORMATION);
static void log(const wchar_t *message, ELOG_LEVEL ll = ELL_INFORMATION);
// The string ": " is added between message and hint
static void log(const c8 *message, const c8 *hint, ELOG_LEVEL ll = ELL_INFORMATION);

View File

@ -648,6 +648,9 @@ if(BUILD_CLIENT)
if(BUILD_UNITTESTS OR BUILD_BENCHMARKS)
target_link_libraries(${PROJECT_NAME} Catch2::Catch2)
endif()
if(BUILD_WITH_TRACY)
target_link_libraries(${PROJECT_NAME} Tracy::TracyClient)
endif()
if(PRECOMPILE_HEADERS)
target_precompile_headers(${PROJECT_NAME} PRIVATE ${PRECOMPILED_HEADERS_LIST})
@ -715,6 +718,9 @@ if(BUILD_SERVER)
if(BUILD_UNITTESTS OR BUILD_BENCHMARKS)
target_link_libraries(${PROJECT_NAME}server Catch2::Catch2)
endif()
if(BUILD_WITH_TRACY)
target_link_libraries(${PROJECT_NAME}server Tracy::TracyClient)
endif()
if(PRECOMPILE_HEADERS)
target_precompile_headers(${PROJECT_NAME}server PRIVATE ${PRECOMPILED_HEADERS_LIST})

View File

@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "version.h"
#include "renderingengine.h"
#include "network/networkexceptions.h"
#include "util/tracy_wrapper.h"
#include <IGUISpriteBank.h>
#include <ICameraSceneNode.h>
#include <unordered_map>
@ -139,8 +140,10 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
// Create the menu clouds
// This is only global so it can be used by RenderingEngine::draw_load_screen().
assert(!g_menucloudsmgr && !g_menuclouds);
std::unique_ptr<IWritableShaderSource> ssrc(createShaderSource());
ssrc->addShaderConstantSetterFactory(new FogShaderConstantSetterFactory());
g_menucloudsmgr = m_rendering_engine->get_scene_manager()->createNewSceneManager();
g_menuclouds = new Clouds(g_menucloudsmgr, nullptr, -1, rand());
g_menuclouds = new Clouds(g_menucloudsmgr, ssrc.get(), -1, rand());
g_menuclouds->setHeight(100.0f);
g_menuclouds->update(v3f(0, 0, 0), video::SColor(255, 240, 240, 255));
scene::ICameraSceneNode* camera;
@ -544,15 +547,19 @@ void ClientLauncher::main_menu(MainMenuData *menudata)
video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
infostream << "Waiting for other menus" << std::endl;
auto framemarker = FrameMarker("ClientLauncher::main_menu()-wait-frame").started();
while (m_rendering_engine->run() && !*kill) {
if (!isMenuActive())
break;
driver->beginScene(true, true, video::SColor(255, 128, 128, 128));
m_rendering_engine->get_gui_env()->drawAll();
driver->endScene();
framemarker.end();
// On some computers framerate doesn't seem to be automatically limited
sleep_ms(25);
framemarker.start();
}
framemarker.end();
infostream << "Waited for other menus" << std::endl;
auto *cur_control = m_rendering_engine->get_raw_device()->getCursorControl();

View File

@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h"
#include "camera.h" // CameraModes
#include "util/basic_macros.h"
#include "util/tracy_wrapper.h"
#include "client/renderingengine.h"
#include <queue>
@ -714,6 +715,8 @@ void ClientMap::touchMapBlocks()
void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
{
ZoneScoped;
bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
std::string prefix;

View File

@ -28,11 +28,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h"
#include <cmath>
// Menu clouds are created later
class Clouds;
Clouds *g_menuclouds = NULL;
scene::ISceneManager *g_menucloudsmgr = NULL;
scene::ISceneManager *g_menucloudsmgr = nullptr;
Clouds *g_menuclouds = nullptr;
// Constant for now
static constexpr const float cloud_size = BS * 64.0f;
@ -49,9 +47,8 @@ Clouds::Clouds(scene::ISceneManager* mgr, IShaderSource *ssrc,
scene::ISceneNode(mgr->getRootSceneNode(), mgr, id),
m_seed(seed)
{
assert(ssrc);
m_enable_shaders = g_settings->getBool("enable_shaders");
// menu clouds use shader-less clouds for simplicity (ssrc == NULL)
m_enable_shaders = m_enable_shaders && ssrc;
m_material.Lighting = false;
m_material.BackfaceCulling = true;

View File

@ -36,11 +36,11 @@ namespace irr::scene
}
// Menu clouds
// The mainmenu and the loading screen use the same Clouds object so that the
// clouds don't jump when switching between the two.
class Clouds;
extern Clouds *g_menuclouds;
// Scene manager used for menu clouds
extern scene::ISceneManager *g_menucloudsmgr;
extern Clouds *g_menuclouds;
class Clouds : public scene::ISceneNode
{

View File

@ -186,6 +186,12 @@ static bool logOnce(const std::ostringstream &from, std::ostream &log_to)
return true;
}
static void setEmissiveColor(scene::ISceneNode *node, video::SColor color)
{
for (u32 i = 0; i < node->getMaterialCount(); ++i)
node->getMaterial(i).EmissiveColor = color;
}
/*
TestCAO
*/
@ -774,8 +780,6 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
// set vertex colors to ensure alpha is set
setMeshColor(m_animated_meshnode->getMesh(), video::SColor(0xFFFFFFFF));
setAnimatedMeshColor(m_animated_meshnode, video::SColor(0xFFFFFFFF));
setSceneNodeMaterials(m_animated_meshnode);
m_animated_meshnode->forEachMaterial([this] (auto &mat) {
@ -810,15 +814,21 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
}
/* Set VBO hint */
// - if shaders are disabled we modify the mesh often
// - sprites are also modified often
// - the wieldmesh sets its own hint
// - bone transformations do not need to modify the vertex data
// wieldmesh sets its own hint, no need to handle it
if (m_enable_shaders && (m_meshnode || m_animated_meshnode)) {
if (m_meshnode)
// sprite uses vertex animation
if (m_meshnode && m_prop.visual != "upright_sprite")
m_meshnode->getMesh()->setHardwareMappingHint(scene::EHM_STATIC);
if (m_animated_meshnode)
m_animated_meshnode->getMesh()->setHardwareMappingHint(scene::EHM_STATIC);
if (m_animated_meshnode) {
auto *mesh = m_animated_meshnode->getMesh();
// skinning happens on the CPU
if (m_animated_meshnode->getJointCount() > 0)
mesh->setHardwareMappingHint(scene::EHM_STREAM, scene::EBT_VERTEX);
else
mesh->setHardwareMappingHint(scene::EHM_STATIC, scene::EBT_VERTEX);
mesh->setHardwareMappingHint(scene::EHM_STATIC, scene::EBT_INDEX);
}
}
/* don't update while punch texture modifier is active */
@ -923,26 +933,15 @@ void GenericCAO::setNodeLight(const video::SColor &light_color)
}
if (m_enable_shaders) {
if (m_prop.visual == "upright_sprite") {
if (!m_meshnode)
return;
for (u32 i = 0; i < m_meshnode->getMaterialCount(); ++i)
m_meshnode->getMaterial(i).EmissiveColor = light_color;
} else {
scene::ISceneNode *node = getSceneNode();
if (!node)
return;
for (u32 i = 0; i < node->getMaterialCount(); ++i) {
video::SMaterial &material = node->getMaterial(i);
material.EmissiveColor = light_color;
}
}
auto *node = getSceneNode();
if (!node)
return;
setEmissiveColor(node, light_color);
} else {
if (m_meshnode) {
setMeshColor(m_meshnode->getMesh(), light_color);
} else if (m_animated_meshnode) {
setAnimatedMeshColor(m_animated_meshnode, light_color);
setMeshColor(m_animated_meshnode->getMesh(), light_color);
} else if (m_spritenode) {
m_spritenode->setColor(light_color);
}
@ -1404,7 +1403,6 @@ void GenericCAO::updateTextures(std::string mod)
material.MaterialType = m_material_type;
material.MaterialTypeParam = m_material_type_param;
material.TextureLayers[0].Texture = texture;
material.Lighting = true;
material.BackfaceCulling = m_prop.backface_culling;
// don't filter low-res textures, makes them look blurry

View File

@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/basic_macros.h"
#include "util/numeric.h"
#include "util/directiontables.h"
#include "util/tracy_wrapper.h"
#include "mapblock_mesh.h"
#include "settings.h"
#include "nodedef.h"
@ -1750,6 +1751,8 @@ void MapblockMeshGenerator::drawNode()
void MapblockMeshGenerator::generate()
{
ZoneScoped;
for (cur_node.p.Z = 0; cur_node.p.Z < data->side_length; cur_node.p.Z++)
for (cur_node.p.Y = 0; cur_node.p.Y < data->side_length; cur_node.p.Y++)
for (cur_node.p.X = 0; cur_node.p.X < data->side_length; cur_node.p.X++) {

View File

@ -79,6 +79,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "hud.h"
#include "clientdynamicinfo.h"
#include <IAnimatedMeshSceneNode.h>
#include "util/tracy_wrapper.h"
#if USE_SOUND
#include "client/sound/sound_openal.h"
@ -1140,6 +1141,8 @@ bool Game::startup(bool *kill,
void Game::run()
{
ZoneScoped;
ProfilerGraph graph;
RunStats stats = {};
CameraOrientation cam_view_target = {};
@ -1167,15 +1170,21 @@ void Game::run()
const bool initial_window_maximized = !g_settings->getBool("fullscreen") &&
g_settings->getBool("window_maximized");
auto framemarker = FrameMarker("Game::run()-frame").started();
while (m_rendering_engine->run()
&& !(*kill || g_gamecallback->shutdown_requested
|| (server && server->isShutdownRequested()))) {
framemarker.end();
// Calculate dtime =
// m_rendering_engine->run() from this iteration
// + Sleep time until the wanted FPS are reached
draw_times.limit(device, &dtime, g_menumgr.pausesGame());
framemarker.start();
const auto current_dynamic_info = ClientDynamicInfo::getCurrent();
if (!current_dynamic_info.equal(client_display_info)) {
client_display_info = current_dynamic_info;
@ -1232,6 +1241,8 @@ void Game::run()
}
}
framemarker.end();
RenderingEngine::autosaveScreensizeAndCo(initial_screen_size, initial_window_maximized);
}
@ -1671,9 +1682,13 @@ bool Game::connectToServer(const GameStartData &start_data,
fps_control.reset();
auto framemarker = FrameMarker("Game::connectToServer()-frame").started();
while (m_rendering_engine->run()) {
framemarker.end();
fps_control.limit(device, &dtime);
framemarker.start();
// Update client and server
step(dtime);
@ -1719,6 +1734,7 @@ bool Game::connectToServer(const GameStartData &start_data,
// Update status
showOverlayMessage(N_("Connecting to server..."), dtime, 20);
}
framemarker.end();
} catch (con::PeerNotFoundException &e) {
warningstream << "This should not happen. Please report a bug." << std::endl;
return false;
@ -1736,9 +1752,11 @@ bool Game::getServerContent(bool *aborted)
fps_control.reset();
auto framemarker = FrameMarker("Game::getServerContent()-frame").started();
while (m_rendering_engine->run()) {
framemarker.end();
fps_control.limit(device, &dtime);
framemarker.start();
// Update client and server
step(dtime);
@ -1804,6 +1822,7 @@ bool Game::getServerContent(bool *aborted)
texture_src, dtime, progress);
}
}
framemarker.end();
*aborted = true;
infostream << "Connect aborted [device]" << std::endl;
@ -2773,6 +2792,8 @@ void Game::updatePauseState()
inline void Game::step(f32 dtime)
{
ZoneScoped;
if (server) {
float fps_max = (!device->isWindowFocused() || g_menumgr.pausesGame()) ?
g_settings->getFloat("fps_max_unfocused") :
@ -4052,6 +4073,7 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
const CameraOrientation &cam)
{
ZoneScoped;
TimeTaker tt_update("Game::updateFrame()");
LocalPlayer *player = client->getEnv().getLocalPlayer();
@ -4311,6 +4333,8 @@ void Game::updateShadows()
void Game::drawScene(ProfilerGraph *graph, RunStats *stats)
{
ZoneScoped;
const video::SColor fog_color = this->sky->getFogColor();
const video::SColor sky_color = this->sky->getSkyColor();

View File

@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "minimap.h"
#include "content_mapblock.h"
#include "util/directiontables.h"
#include "util/tracy_wrapper.h"
#include "client/meshgen/collector.h"
#include "client/renderingengine.h"
#include <array>
@ -611,6 +612,8 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
m_last_crack(-1),
m_last_daynight_ratio((u32) -1)
{
ZoneScoped;
for (auto &m : m_mesh)
m = new scene::SMesh();
m_enable_shaders = data->m_use_shaders;

View File

@ -34,7 +34,7 @@ inline static void applyShadeFactor(video::SColor& color, float factor)
color.setBlue(core::clamp(core::round32(color.getBlue()*factor), 0, 255));
}
void applyFacesShading(video::SColor &color, const v3f &normal)
void applyFacesShading(video::SColor &color, const v3f normal)
{
/*
Some drawtypes have normals set to (0, 0, 0), this must result in
@ -133,6 +133,7 @@ void scaleMesh(scene::IMesh *mesh, v3f scale)
for (u32 i = 0; i < vertex_count; i++)
((video::S3DVertex *)(vertices + i * stride))->Pos *= scale;
buf->setDirty(scene::EBT_VERTEX);
buf->recalculateBoundingBox();
// calculate total bounding box
@ -161,6 +162,7 @@ void translateMesh(scene::IMesh *mesh, v3f vec)
for (u32 i = 0; i < vertex_count; i++)
((video::S3DVertex *)(vertices + i * stride))->Pos += vec;
buf->setDirty(scene::EBT_VERTEX);
buf->recalculateBoundingBox();
// calculate total bounding box
@ -172,23 +174,17 @@ void translateMesh(scene::IMesh *mesh, v3f vec)
mesh->setBoundingBox(bbox);
}
void setMeshBufferColor(scene::IMeshBuffer *buf, const video::SColor &color)
void setMeshBufferColor(scene::IMeshBuffer *buf, const video::SColor color)
{
const u32 stride = getVertexPitchFromType(buf->getVertexType());
u32 vertex_count = buf->getVertexCount();
u8 *vertices = (u8 *) buf->getVertices();
for (u32 i = 0; i < vertex_count; i++)
((video::S3DVertex *) (vertices + i * stride))->Color = color;
buf->setDirty(scene::EBT_VERTEX);
}
void setAnimatedMeshColor(scene::IAnimatedMeshSceneNode *node, const video::SColor &color)
{
for (u32 i = 0; i < node->getMaterialCount(); ++i) {
node->getMaterial(i).EmissiveColor = color;
}
}
void setMeshColor(scene::IMesh *mesh, const video::SColor &color)
void setMeshColor(scene::IMesh *mesh, const video::SColor color)
{
if (mesh == NULL)
return;
@ -209,6 +205,7 @@ static void applyToMesh(scene::IMesh *mesh, const F &fn)
char *vertices = reinterpret_cast<char *>(buf->getVertices());
for (u32 i = 0; i < vertex_count; i++)
fn(reinterpret_cast<video::S3DVertex *>(vertices + i * stride));
buf->setDirty(scene::EBT_VERTEX);
}
}
@ -225,6 +222,7 @@ void colorizeMeshBuffer(scene::IMeshBuffer *buf, const video::SColor *buffercolo
// Apply shading
applyFacesShading(*vc, vertex->Normal);
}
buf->setDirty(scene::EBT_VERTEX);
}
void setMeshColorByNormalXYZ(scene::IMesh *mesh,

View File

@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
* Applies shading to a color based on the surface's
* normal vector.
*/
void applyFacesShading(video::SColor &color, const v3f &normal);
void applyFacesShading(video::SColor &color, const v3f normal);
/*
Create a new cube mesh.
@ -52,17 +52,12 @@ void translateMesh(scene::IMesh *mesh, v3f vec);
/*!
* Sets a constant color for all vertices in the mesh buffer.
*/
void setMeshBufferColor(scene::IMeshBuffer *buf, const video::SColor &color);
void setMeshBufferColor(scene::IMeshBuffer *buf, const video::SColor color);
/*
Set a constant color for all vertices in the mesh
*/
void setMeshColor(scene::IMesh *mesh, const video::SColor &color);
/*
Set a constant color for an animated mesh
*/
void setAnimatedMeshColor(scene::IAnimatedMeshSceneNode *node, const video::SColor &color);
void setMeshColor(scene::IMesh *mesh, const video::SColor color);
/*!
* Overwrites the color of a mesh buffer.

View File

@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <ISceneManager.h>
#include <ICameraSceneNode.h>
#include <S3DVertex.h>
#include "client/mesh.h"
#include "client/tile.h"
#include "noise.h" // easeCurve
#include "profiler.h"
@ -77,10 +78,9 @@ Sky::Sky(s32 id, RenderingEngine *rendering_engine, ITextureSource *tsrc, IShade
// Create materials
m_materials[0] = baseMaterial();
// FIXME: shouldn't this check m_enable_shaders?
m_materials[0].MaterialType = ssrc->getShaderInfo(ssrc->getShader("stars_shader", TILE_MATERIAL_ALPHA)).material;
m_materials[0].Lighting = true;
m_materials[0].ColorMaterial = video::ECM_NONE;
m_materials[0].MaterialType = m_enable_shaders ?
ssrc->getShaderInfo(ssrc->getShader("stars_shader", TILE_MATERIAL_ALPHA)).material :
video::EMT_TRANSPARENT_ALPHA_CHANNEL;
m_materials[1] = baseMaterial();
m_materials[1].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
@ -688,7 +688,10 @@ void Sky::draw_stars(video::IVideoDriver * driver, float wicked_time_of_day)
color.a *= alpha;
if (color.a <= 0.0f) // Stars are only drawn when not fully transparent
return;
m_materials[0].EmissiveColor = color.toSColor();
if (m_enable_shaders)
m_materials[0].EmissiveColor = color.toSColor();
else
setMeshBufferColor(m_stars.get(), color.toSColor());
auto sky_rotation = core::matrix4().setRotationAxisRadians(2.0f * M_PI * (wicked_time_of_day - 0.25f), v3f(0.0f, 0.0f, 1.0f));
auto world_matrix = driver->getTransform(video::ETS_WORLD);
@ -835,7 +838,6 @@ void Sky::updateStars()
vertices.reserve(4 * m_star_params.count);
indices.reserve(6 * m_star_params.count);
video::SColor fallback_color = m_star_params.starcolor; // used on GLES 2 “without shaders”
PcgRandom rgen(m_seed);
float d = (0.006 / 2) * m_star_params.scale;
for (u16 i = 0; i < m_star_params.count; i++) {
@ -854,10 +856,10 @@ void Sky::updateStars()
a.rotateVect(p1);
a.rotateVect(p2);
a.rotateVect(p3);
vertices.push_back(video::S3DVertex(p, {}, fallback_color, {}));
vertices.push_back(video::S3DVertex(p1, {}, fallback_color, {}));
vertices.push_back(video::S3DVertex(p2, {}, fallback_color, {}));
vertices.push_back(video::S3DVertex(p3, {}, fallback_color, {}));
vertices.push_back(video::S3DVertex(p, {}, {}, {}));
vertices.push_back(video::S3DVertex(p1, {}, {}, {}));
vertices.push_back(video::S3DVertex(p2, {}, {}, {}));
vertices.push_back(video::S3DVertex(p3, {}, {}, {}));
}
for (u16 i = 0; i < m_star_params.count; i++) {
indices.push_back(i * 4 + 0);
@ -867,7 +869,8 @@ void Sky::updateStars()
indices.push_back(i * 4 + 3);
indices.push_back(i * 4 + 0);
}
m_stars->setHardwareMappingHint(scene::EHM_STATIC);
if (m_enable_shaders)
m_stars->setHardwareMappingHint(scene::EHM_STATIC);
}
void Sky::setSkyColors(const SkyColor &sky_color)

View File

@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "sound_singleton.h"
#include "util/numeric.h" // myrand()
#include "util/tracy_wrapper.h"
#include "filesys.h"
#include "porting.h"
@ -501,6 +502,8 @@ void *OpenALSoundManager::run()
u64 t_step_start = porting::getTimeMs();
while (true) {
auto framemarker = FrameMarker("OpenALSoundManager::run()-frame").started();
auto get_time_since_last_step = [&] {
return (f32)(porting::getTimeMs() - t_step_start);
};

View File

@ -41,3 +41,4 @@
#cmakedefine01 BUILD_UNITTESTS
#cmakedefine01 BUILD_BENCHMARKS
#cmakedefine01 USE_SDL2
#cmakedefine01 BUILD_WITH_TRACY

View File

@ -40,6 +40,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <ICameraSceneNode.h>
#include <IGUIStaticText.h>
#include "client/imagefilters.h"
#include "util/tracy_wrapper.h"
#if USE_SOUND
#include "client/sound/sound_openal.h"
@ -141,10 +142,6 @@ GUIEngine::GUIEngine(JoystickController *joystick,
// create texture source
m_texture_source = std::make_unique<MenuTextureSource>(rendering_engine->get_video_driver());
// create shader source
// (currently only used by clouds)
m_shader_source.reset(createShaderSource());
// create soundmanager
#if USE_SOUND
if (g_settings->getBool("enable_sound") && g_sound_manager_singleton.get()) {
@ -295,10 +292,6 @@ void GUIEngine::run()
IrrlichtDevice *device = m_rendering_engine->get_raw_device();
video::IVideoDriver *driver = device->getVideoDriver();
// Always create clouds because they may or may not be
// needed based on the game selected
cloudInit();
unsigned int text_height = g_fontengine->getTextHeight();
// Reset fog color
@ -329,9 +322,12 @@ void GUIEngine::run()
fps_control.reset();
while (m_rendering_engine->run() && !m_startgame && !m_kill) {
auto framemarker = FrameMarker("GUIEngine::run()-frame").started();
while (m_rendering_engine->run() && !m_startgame && !m_kill) {
framemarker.end();
fps_control.limit(device, &dtime);
framemarker.start();
if (device->isWindowVisible()) {
// check if we need to update the "upper left corner"-text
@ -371,6 +367,7 @@ void GUIEngine::run()
m_menu->getAndroidUIInput();
#endif
}
framemarker.end();
m_script->beforeClose();
@ -390,8 +387,6 @@ GUIEngine::~GUIEngine()
m_irr_toplefttext->remove();
m_cloud.clouds.reset();
// delete textures
for (image_definition &texture : m_textures) {
if (texture.texture)
@ -399,26 +394,11 @@ GUIEngine::~GUIEngine()
}
}
/******************************************************************************/
void GUIEngine::cloudInit()
{
m_shader_source->addShaderConstantSetterFactory(
new FogShaderConstantSetterFactory());
m_cloud.clouds = make_irr<Clouds>(m_smgr, m_shader_source.get(), -1, rand());
m_cloud.clouds->setHeight(100.0f);
m_cloud.clouds->update(v3f(0, 0, 0), video::SColor(255,240,240,255));
m_cloud.camera = m_smgr->addCameraSceneNode(0,
v3f(0,0,0), v3f(0, 60, 100));
m_cloud.camera->setFarValue(10000);
}
/******************************************************************************/
void GUIEngine::drawClouds(float dtime)
{
m_cloud.clouds->step(dtime*3);
m_smgr->drawAll();
g_menuclouds->step(dtime * 3);
g_menucloudsmgr->drawAll();
}
/******************************************************************************/

View File

@ -203,8 +203,6 @@ private:
MainMenuData *m_data = nullptr;
/** texture source */
std::unique_ptr<ISimpleTextureSource> m_texture_source;
/** shader source */
std::unique_ptr<IWritableShaderSource> m_shader_source;
/** sound manager */
std::unique_ptr<ISoundManager> m_sound_manager;
@ -279,23 +277,11 @@ private:
/** and text that is in it */
EnrichedString m_toplefttext;
/** initialize cloud subsystem */
void cloudInit();
/** do preprocessing for cloud subsystem */
void drawClouds(float dtime);
/** internam data required for drawing clouds */
struct clouddata {
/** pointer to cloud class */
irr_ptr<Clouds> clouds;
/** camera required for drawing clouds */
scene::ICameraSceneNode *camera = nullptr;
};
/** is drawing of clouds enabled atm */
bool m_clouds_enabled = true;
/** data used to draw clouds */
clouddata m_cloud;
bool m_clouds_enabled = true;
static void fullscreenChangedCallback(const std::string &name, void *data);
};

View File

@ -73,6 +73,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "filesys.h"
#include "log.h"
#include "util/string.h"
#include "util/tracy_wrapper.h"
#include <vector>
#include <cstdarg>
#include <cstdio>
@ -960,6 +961,8 @@ void TrackFreedMemory(size_t amount)
void TriggerMemoryTrim()
{
ZoneScoped;
constexpr auto MO = std::memory_order_relaxed;
if (memory_freed.load(MO) >= MEMORY_TRIM_THRESHOLD) {
// Synchronize call

View File

@ -32,6 +32,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "client/client.h"
#endif
#if BUILD_WITH_TRACY
#include "tracy/TracyLua.hpp"
#endif
extern "C" {
#include "lualib.h"
@ -95,6 +98,11 @@ ScriptApiBase::ScriptApiBase(ScriptingType type):
lua_pushstring(m_luastack, LUA_BITLIBNAME);
lua_call(m_luastack, 1, 0);
#if BUILD_WITH_TRACY
// Load tracy lua bindings
tracy::LuaRegister(m_luastack);
#endif
// Make the ScriptApiBase* accessible to ModApiBase
#if INDIRECT_SCRIPTAPI_RIDX
*(void **)(lua_newuserdata(m_luastack, sizeof(void *))) = this;

View File

@ -109,7 +109,12 @@ void ScriptApiSecurity::initializeSecurity()
"string",
"table",
"math",
"bit"
"bit",
// Not sure if completely safe. But if someone enables tracy, they'll
// know what they do.
#if BUILD_WITH_TRACY
"tracy",
#endif
};
static const char *io_whitelist[] = {
"close",
@ -303,6 +308,11 @@ void ScriptApiSecurity::initializeSecurityClient()
"table",
"math",
"bit",
// Not sure if completely safe. But if someone enables tracy, they'll
// know what they do.
#if BUILD_WITH_TRACY
"tracy",
#endif
};
static const char *os_whitelist[] = {
"clock",

View File

@ -75,6 +75,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "gameparams.h"
#include "particles.h"
#include "gettext.h"
#include "util/tracy_wrapper.h"
class ClientNotFoundException : public BaseException
{
@ -101,6 +102,8 @@ private:
void *ServerThread::run()
{
ZoneScoped;
BEGIN_DEBUG_EXCEPTION_HANDLER
/*
@ -110,6 +113,7 @@ void *ServerThread::run()
* server-step frequency. Receive() is used for waiting between the steps.
*/
auto framemarker = FrameMarker("ServerThread::run()-frame").started();
try {
m_server->AsyncRunStep(0.0f, true);
} catch (con::ConnectionBindFailed &e) {
@ -119,10 +123,12 @@ void *ServerThread::run()
} catch (ModError &e) {
m_server->setAsyncFatalError(e.what());
}
framemarker.end();
float dtime = 0.0f;
while (!stopRequested()) {
framemarker.start();
ScopeProfiler spm(g_profiler, "Server::RunStep() (max)", SPT_MAX);
u64 t0 = porting::getTimeUs();
@ -149,6 +155,7 @@ void *ServerThread::run()
}
dtime = 1e-6f * (porting::getTimeUs() - t0);
framemarker.end();
}
END_DEBUG_EXCEPTION_HANDLER
@ -607,6 +614,9 @@ void Server::step()
void Server::AsyncRunStep(float dtime, bool initial_step)
{
ZoneScoped;
auto framemarker = FrameMarker("Server::AsyncRunStep()-frame").started();
{
// Send blocks to clients
SendBlocks(dtime);
@ -1055,6 +1065,9 @@ void Server::AsyncRunStep(float dtime, bool initial_step)
void Server::Receive(float timeout)
{
ZoneScoped;
auto framemarker = FrameMarker("Server::Receive()-frame").started();
const u64 t0 = porting::getTimeUs();
const float timeout_us = timeout * 1e6f;
auto remaining_time_us = [&]() -> float {

200
src/util/tracy_wrapper.h Normal file
View File

@ -0,0 +1,200 @@
/*
Minetest
Copyright (C) 2024 DS
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* Wrapper for <tracy/Tracy.hpp>, so that we can use Tracy's macros without
* having it as mandatory dependency.
*
* For annotations that you don't intend to upstream, you can also include
* <tracy/Tracy.hpp> directly (which also works in irr/).
*/
#pragma once
#include "config.h"
#include "util/basic_macros.h"
#if BUILD_WITH_TRACY
#include <tracy/Tracy.hpp> // IWYU pragma: export
#else
// Copied from Tracy.hpp
#define TracyNoop
#define ZoneNamed(x,y)
#define ZoneNamedN(x,y,z)
#define ZoneNamedC(x,y,z)
#define ZoneNamedNC(x,y,z,w)
#define ZoneTransient(x,y)
#define ZoneTransientN(x,y,z)
#define ZoneScoped
#define ZoneScopedN(x)
#define ZoneScopedC(x)
#define ZoneScopedNC(x,y)
#define ZoneText(x,y)
#define ZoneTextV(x,y,z)
#define ZoneTextF(x,...)
#define ZoneTextVF(x,y,...)
#define ZoneName(x,y)
#define ZoneNameV(x,y,z)
#define ZoneNameF(x,...)
#define ZoneNameVF(x,y,...)
#define ZoneColor(x)
#define ZoneColorV(x,y)
#define ZoneValue(x)
#define ZoneValueV(x,y)
#define ZoneIsActive false
#define ZoneIsActiveV(x) false
#define FrameMark
#define FrameMarkNamed(x)
#define FrameMarkStart(x)
#define FrameMarkEnd(x)
#define FrameImage(x,y,z,w,a)
#define TracyLockable( type, varname ) type varname
#define TracyLockableN( type, varname, desc ) type varname
#define TracySharedLockable( type, varname ) type varname
#define TracySharedLockableN( type, varname, desc ) type varname
#define LockableBase( type ) type
#define SharedLockableBase( type ) type
#define LockMark(x) (void)x
#define LockableName(x,y,z)
#define TracyPlot(x,y)
#define TracyPlotConfig(x,y,z,w,a)
#define TracyMessage(x,y)
#define TracyMessageL(x)
#define TracyMessageC(x,y,z)
#define TracyMessageLC(x,y)
#define TracyAppInfo(x,y)
#define TracyAlloc(x,y)
#define TracyFree(x)
#define TracySecureAlloc(x,y)
#define TracySecureFree(x)
#define TracyAllocN(x,y,z)
#define TracyFreeN(x,y)
#define TracySecureAllocN(x,y,z)
#define TracySecureFreeN(x,y)
#define ZoneNamedS(x,y,z)
#define ZoneNamedNS(x,y,z,w)
#define ZoneNamedCS(x,y,z,w)
#define ZoneNamedNCS(x,y,z,w,a)
#define ZoneTransientS(x,y,z)
#define ZoneTransientNS(x,y,z,w)
#define ZoneScopedS(x)
#define ZoneScopedNS(x,y)
#define ZoneScopedCS(x,y)
#define ZoneScopedNCS(x,y,z)
#define TracyAllocS(x,y,z)
#define TracyFreeS(x,y)
#define TracySecureAllocS(x,y,z)
#define TracySecureFreeS(x,y)
#define TracyAllocNS(x,y,z,w)
#define TracyFreeNS(x,y,z)
#define TracySecureAllocNS(x,y,z,w)
#define TracySecureFreeNS(x,y,z)
#define TracyMessageS(x,y,z)
#define TracyMessageLS(x,y)
#define TracyMessageCS(x,y,z,w)
#define TracyMessageLCS(x,y,z)
#define TracySourceCallbackRegister(x,y)
#define TracyParameterRegister(x,y)
#define TracyParameterSetup(x,y,z,w)
#define TracyIsConnected false
#define TracyIsStarted false
#define TracySetProgramName(x)
#define TracyFiberEnter(x)
#define TracyFiberEnterHint(x,y)
#define TracyFiberLeave
#endif
// Helper for making sure frames end in all possible control flow path
class FrameMarker
{
const char *m_name;
bool m_started = false;
public:
FrameMarker(const char *name) : m_name(name) {}
~FrameMarker() { end(); }
DISABLE_CLASS_COPY(FrameMarker)
FrameMarker(FrameMarker &&other) noexcept :
m_name(other.m_name), m_started(other.m_started)
{
other.m_started = false;
}
FrameMarker &operator=(FrameMarker &&other) noexcept
{
if (&other != this) {
end();
m_name = other.m_name;
m_started = other.m_started;
other.m_started = false;
}
return *this;
}
FrameMarker &&started() &&
{
if (!m_started) {
FrameMarkStart(m_name);
m_started = true;
}
return std::move(*this);
}
void start()
{
// no move happens, because we drop the reference
(void)std::move(*this).started();
}
void end()
{
if (m_started) {
m_started = false;
FrameMarkEnd(m_name);
}
}
};