the other thing I was working on (main thread metrics)

This commit is contained in:
ecker 2026-05-04 21:49:29 -05:00
parent 89ca3efb3e
commit f0d552c47b
4 changed files with 71 additions and 73 deletions

View File

@ -309,21 +309,6 @@
"jitter scale": 0.0625,
"preset": "native" // native (1x), quality (1.5x), balanced (1.7x), performance (2.0x), ultra (3.0x)
},
"reactphysics": {
"global storage": false,
"timescale": 0.01666666666, // 0.03333333333,
"interpolate": true,
"gravity": {
"mode": "default", // default / per-object / universal
"constant": 6.67408e-11
},
"debug draw": {
"enabled": false,
"line width": 8,
"layer": "Gui",
"rate": 0.0125
}
},
"vr" : {
"enable" : false,
"manifest": "./data/openvr_manifest.json",
@ -349,7 +334,7 @@
}
},
"memory pool": {
"enabled": true, // needs to be kept on for GC
"enabled": true,
"subPools": true,
"alignment": 64,
"override": true,
@ -363,7 +348,7 @@
"render modes": { "gui": true, "deferred": true },
"limiters": {
"deltaTime": 5,
"framerate": "auto" // "auto" // for some reason drops to 60
"framerate": "auto"
},
"threads": {
"workers" : "auto",

View File

@ -192,7 +192,6 @@ void main() {
if ( projectedSize < 0.08 ) lodLevel = 2;
if ( projectedSize < 0.02 ) lodLevel = 3;
lodLevel = min(lodLevel, MAX_LODS - 1);
lodLevel = 3;
LOD lod = lodMetadata[drawCommand.instanceID].levels[lodLevel];

View File

@ -726,16 +726,8 @@ void UF_API uf::initialize() {
payload["scene"] = uf::config["engine"]["scenes"]["start"];
/*global*/::sceneTransition.payload = payload;
/*global*/::sceneTransition.phase = 0;
// auto& scene = uf::scene::loadScene( uf::config["engine"]["scenes"]["start"] );
}
/*
uf::thread::add( uf::thread::fetchWorker(), [&]{
uf::asset::processQueue();
});
*/
uf::ready = true;
UF_MSG_INFO("EXT took {} seconds to initialize", /*global*/::times.sys.elapsed().asDouble());
}
@ -743,13 +735,20 @@ void UF_API uf::initialize() {
void UF_API uf::tick() {
++uf::time::frame;
static pod::Thread& threadMain = uf::thread::get(uf::thread::mainThreadName);
#if UF_THREAD_METRICS
auto activeStart = std::chrono::high_resolution_clock::now();
#endif
#if 1
// skip the next tick to load the next scene to ensure nothing's happening
if ( /*global*/::sceneTransition.phase >= 0 ) {
auto target = /*global*/::sceneTransition.payload["scene"].as<uf::stl::string>();
auto& phase = /*global*/::sceneTransition.phase;
++phase;
// might be necessary since i bluescreened with a dedicated thread
#if UF_USE_VULKAN
uf::renderer::flushCommandBuffers();
#endif
@ -775,9 +774,6 @@ void UF_API uf::tick() {
uf::renderer::flushCommandBuffers();
#endif
uf::renderer::synchronize();
// uf::scene::tick();
// uf::renderer::tick();
return;
}
@ -844,7 +840,7 @@ void UF_API uf::tick() {
}
/* Tick Main Thread Queue */ {
uf::thread::process( uf::thread::get(uf::thread::mainThreadName) );
uf::thread::process( threadMain );
}
#if UF_USE_ULTRALIGHT
/* Ultralight-UX */ if ( /*global*/::config.engine.ext.ultralight.enabled ) {
@ -865,6 +861,66 @@ void UF_API uf::tick() {
ext::imgui::tick();
}
#endif
// perform GC on entities
if ( /*global*/::config.engine.gc.enabled ) {
TIMER( /*global*/::config.engine.gc.every ) {
size_t collected = uf::instantiator::collect( /*global*/::config.engine.gc.mode );
if ( collected > 0 ) {
if ( /*global*/::config.engine.gc.announce ) UF_MSG_DEBUG("GC collected {} unused entities", (int) collected);
}
}
}
#if UF_THREAD_METRICS
// Mark the end of active work and the start of idle/sleep time
auto idleStart = std::chrono::high_resolution_clock::now();
#endif
#if !UF_ENV_DREAMCAST
if ( /*global*/::times.limiter > 0 ) {
static auto nextFrameTime = std::chrono::steady_clock::now();
double limiterMs = /*global*/::times.limiter * 1000.0;
auto limiterDuration = std::chrono::duration_cast<std::chrono::steady_clock::duration>(std::chrono::duration<double, std::milli>(limiterMs));
nextFrameTime += limiterDuration;
auto now = std::chrono::steady_clock::now();
if ( now < nextFrameTime ) {
auto timeRemaining = nextFrameTime - now;
if ( timeRemaining > std::chrono::milliseconds(2) ) std::this_thread::sleep_for(timeRemaining - std::chrono::milliseconds(1));
while ( std::chrono::steady_clock::now() < nextFrameTime ) std::this_thread::yield();
} else {
nextFrameTime = std::chrono::steady_clock::now();
}
}
auto& controller = uf::scene::getCurrentScene().getController();
if ( /*global*/::requestDedicatedRenderThread && controller.getName() == "Player" ) {
/*global*/::requestDedicatedRenderThread = false;
uf::renderer::settings::experimental::dedicatedThread = true;
UF_MSG_DEBUG("Dedicated render requested");
}
#if UF_USE_VULKAN
if ( /*global*/::requestDeferredCommandBufferSubmit && controller.getName() == "Player" ) {
/*global*/::requestDeferredCommandBufferSubmit = false;
uf::renderer::settings::defaultCommandBufferImmediate = false;
UF_MSG_DEBUG("Defer command buffer submit requested");
}
#endif
#endif
#if UF_THREAD_METRICS
auto tickEnd = std::chrono::high_resolution_clock::now();
std::chrono::duration<float, std::milli> activeTime = idleStart - activeStart;
std::chrono::duration<float, std::milli> idleTime = tickEnd - idleStart;
std::chrono::duration<float, std::milli> frameTime = tickEnd - activeStart;
threadMain.metrics.activeTimeMs.store(activeTime.count(), std::memory_order_relaxed);
threadMain.metrics.idleTimeMs.store(idleTime.count(), std::memory_order_relaxed);
threadMain.metrics.totalFrameTimeMs.store(frameTime.count(), std::memory_order_relaxed);
#endif
/* FPS Print */ if ( /*global*/::config.engine.fps.print ) {
++/*global*/::times.frames;
++/*global*/::times.total.frames;
@ -881,48 +937,6 @@ void UF_API uf::tick() {
/*global*/::times.frames = 0;
}
}
auto& controller = uf::scene::getCurrentScene().getController();
// to-do: handle when the memory pool is disabled, because entities are NOT cleaned up at all
// should also handle entity deletion when GC is disabled
if ( /*global*/::config.engine.gc.enabled ) {
TIMER( /*global*/::config.engine.gc.every ) {
size_t collected = uf::instantiator::collect( /*global*/::config.engine.gc.mode );
if ( collected > 0 ) {
if ( /*global*/::config.engine.gc.announce ) UF_MSG_DEBUG("GC collected {} unused entities", (int) collected);
}
}
}
#if !UF_ENV_DREAMCAST
if ( /*global*/::times.limiter > 0 ) {
double limiter = /*global*/::times.limiter * 1000.0;
static uf::Timer<long long> timer(false);
if ( !timer.running() ) timer.start();
auto elapsed = timer.elapsed().asMilliseconds();
if ( elapsed < limiter ) {
std::chrono::duration<double, std::milli> delta(limiter - elapsed);
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(delta);
std::this_thread::sleep_for(std::chrono::milliseconds(duration.count()));
}
timer.reset();
}
if ( /*global*/::requestDedicatedRenderThread && controller.getName() == "Player" ) {
/*global*/::requestDedicatedRenderThread = false;
uf::renderer::settings::experimental::dedicatedThread = true;
UF_MSG_DEBUG("Dedicated render requested");
}
#if UF_USE_VULKAN
if ( /*global*/::requestDeferredCommandBufferSubmit && controller.getName() == "Player" ) {
/*global*/::requestDeferredCommandBufferSubmit = false;
uf::renderer::settings::defaultCommandBufferImmediate = false;
UF_MSG_DEBUG("Defer command buffer submit requested");
}
#endif
#endif
}
void UF_API uf::render() {
if ( uf::scene::scenes.empty() ) return;

View File

@ -66,7 +66,7 @@ bool ext::meshopt::optimize( uf::Mesh& mesh, float simplify, size_t o, bool verb
uf::stl::vector<meshopt_Stream> streams;
for ( auto& attr : mesh.vertex.attributes ) {
const uint8_t* basePtr = (const uint8_t*)attr.pointer + srcVertexOffset * attr.stride;
streams.emplace_back({ basePtr, attr.descriptor.size, attr.stride });
streams.emplace_back(meshopt_Stream{ basePtr, attr.descriptor.size, attr.stride });
}
// deduplicate vertices