Modules/Graphics/private/GraphicApplication.cpp
Шурупов Илья Викторович 37a650b1e8 Add frame profiling, GPU timers and input recording to the libraries
Profiler (Modules) collects per-frame wall and thread CPU time, named
inclusive sections, counters and GPU durations. It is off by default, so
a disabled scope costs one branch. Application, WidgetApplication,
VulkanContext and Canvas mark the frame phases (process, dispatch,
advance, draw, paint, UI flush, acquire, submit, present).

GpuTimer wraps Vulkan timestamp queries in a small ring that is read
without stalling; the window frame and any RenderBuffer that asks for it
report GPU time into the profiler.

InputRecording stores raw window input with exact timing, pen pressure
and tilt as a line-based text file, and InputRecorder captures it
through a new raw tap in the InputCoalescer that sees every platform
event before coalescing.
2026-10-15 20:03:20 +03:00

126 lines
No EOL
2.8 KiB
C++

#include <cstdio>
#include "GraphicApplication.hpp"
#include "Profiler.hpp"
#include "imgui.h"
using namespace tp;
Application::Application() {
mWindow = Window::createWindow({ 1500, 900 });
mGraphics = new Graphics(mWindow);
mPerSecondTimer.setDuration(1000.f);
}
void Application::start() {
mEventHandler = new EventHandler();
mWindow->setEventHandler(mEventHandler);
mWindow->waitForReady();
mPreviousFrameTime = get_time();
mPerSecondTimer.reset();
runFrame();
}
void Application::step(halnf deltaMs) {
mWindow->processEvents(false);
runFrame(deltaMs);
}
void Application::finish() {
mWindow->setEventHandler(nullptr);
delete mEventHandler;
mEventHandler = nullptr;
}
void Application::run() {
start();
while (!mWindow->shouldClose()) {
mWindow->processEvents(!wantsFrame() || mWindow->isWaitingForFrame());
while (mWindow->isWaitingForFrame() && !mWindow->shouldClose())
mWindow->processEvents(true);
runFrame();
}
finish();
}
bool Application::wantsFrame() { return forceNewFrame() || mWindow->hasPendingWork(); }
void Application::runFrame() {
updateGlobalTime();
const time_ms now = get_time();
const halnf deltaMs = halnf(now - mPreviousFrameTime);
mPreviousFrameTime = now;
runFrame(deltaMs);
}
void Application::runFrame(halnf deltaMs) {
mFrameStart = get_time_ns();
Profiler::global().beginFrame();
{
TP_PROFILE_SCOPE("frame.process");
processPendingInput(deltaMs);
}
present();
updateFrameCounters();
Profiler::global().endFrame();
}
void Application::processPendingInput(halnf deltaMs) {
halnf deltaTime = deltaMs;
mWindow->flushPendingInput();
do {
TP_PROFILE_COUNT("input.events", 1);
mEventHandler->processEvent();
processFrame(mEventHandler, deltaTime);
deltaTime = 0;
mFramesProcessed++;
} while (mEventHandler->hasQueuedEvents());
}
void Application::present() {
TP_PROFILE_SCOPE("frame.present");
mGraphics->drawBegin();
{
TP_PROFILE_SCOPE("frame.draw");
drawFrame(mGraphics->getCanvas());
}
mGraphics->drawEnd();
mWindow->draw();
mFramesDrawn++;
}
void Application::updateFrameCounters() {
if (!mPerSecondTimer.isTimeout()) return;
mPerSecondTimer.reset();
mFramesProcessedPerSecond = mFramesProcessed;
mFramesDrawnPerSecond = mFramesDrawn;
mFramesDrawn = 0;
mFramesProcessed = 0;
}
void Application::processFrame(EventHandler* eventHandler, halnf deltaTime) {}
void Application::drawFrame(Canvas* canvas) {
// ImGui::Text("Frames processed per second: %f", mFramesProcessedPerSecond);
// ImGui::Text("Frames drawn per second: %f", mFramesDrawnPerSecond);
}
void Application::drawDebug() {
ImGui::Text("Frames processed per second: %f", this->mFramesProcessedPerSecond);
ImGui::Text("Frames drawn per second: %f", this->mFramesDrawnPerSecond);
}
Application::~Application() {
delete mGraphics;
Window::destroyWindow(mWindow);
}