This commit is contained in:
Johanness
2026-05-19 00:16:16 +03:00
parent ad215f32bc
commit 46c80c88bf
65 changed files with 1189 additions and 319 deletions
+282 -69
View File
@@ -55,6 +55,12 @@ struct PerfStats
struct FramePerfStats
{
uint64_t eventTicks = 0;
uint64_t eventPumpTicks = 0;
uint64_t eventPollTicks = 0;
uint64_t eventProcessTicks = 0;
uint64_t emptyPollTicks = 0;
uint64_t maxEventPollTicks = 0;
uint64_t maxEventProcessTicks = 0;
uint64_t fenceWaitTicks = 0;
uint64_t feedReadTicks = 0;
uint64_t stageCopyTicks = 0;
@@ -70,6 +76,18 @@ struct FramePerfStats
uint64_t acquireTicks = 0;
uint64_t submitPresentTicks = 0;
uint64_t idleDelayTicks = 0;
uint32_t events = 0;
uint32_t windowEvents = 0;
uint32_t resizeEvents = 0;
uint32_t mouseMotionEvents = 0;
uint32_t mouseButtonEvents = 0;
uint32_t mouseWheelEvents = 0;
uint32_t keyboardEvents = 0;
uint32_t textEvents = 0;
uint32_t quitEvents = 0;
uint32_t otherEvents = 0;
uint32_t maxPollEventType = 0;
uint32_t maxProcessEventType = 0;
};
struct FeedPerfStats
@@ -88,6 +106,76 @@ struct FeedPerfStats
bool hasLastGrain = false;
};
static void recordEventStats(
FramePerfStats& framePerf,
const SDL_Event& event)
{
++framePerf.events;
if (event.type >= SDL_EVENT_WINDOW_FIRST &&
event.type <= SDL_EVENT_WINDOW_LAST)
{
++framePerf.windowEvents;
if (event.type == SDL_EVENT_WINDOW_RESIZED ||
event.type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED)
{
++framePerf.resizeEvents;
}
return;
}
switch (event.type)
{
case SDL_EVENT_MOUSE_MOTION:
++framePerf.mouseMotionEvents;
break;
case SDL_EVENT_MOUSE_BUTTON_DOWN:
case SDL_EVENT_MOUSE_BUTTON_UP:
++framePerf.mouseButtonEvents;
break;
case SDL_EVENT_MOUSE_WHEEL:
++framePerf.mouseWheelEvents;
break;
case SDL_EVENT_KEY_DOWN:
case SDL_EVENT_KEY_UP:
++framePerf.keyboardEvents;
break;
case SDL_EVENT_TEXT_EDITING:
case SDL_EVENT_TEXT_INPUT:
case SDL_EVENT_TEXT_EDITING_CANDIDATES:
++framePerf.textEvents;
break;
case SDL_EVENT_QUIT:
++framePerf.quitEvents;
break;
default:
++framePerf.otherEvents;
break;
}
}
static void disableUnusedSdlEvents()
{
// Keep SDL's internal state updates, but avoid queuing noisy events
// that the multiviewer does not consume. On Wayland these showed up
// around SDL_PumpEvents() stalls during compositor/window activity.
SDL_SetEventEnabled(SDL_EVENT_WINDOW_EXPOSED, false);
SDL_SetEventEnabled(SDL_EVENT_WINDOW_FOCUS_GAINED, false);
SDL_SetEventEnabled(SDL_EVENT_WINDOW_FOCUS_LOST, false);
SDL_SetEventEnabled(SDL_EVENT_WINDOW_MOUSE_ENTER, false);
SDL_SetEventEnabled(SDL_EVENT_WINDOW_MOUSE_LEAVE, false);
SDL_SetEventEnabled(SDL_EVENT_MOUSE_MOTION, false);
SDL_SetEventEnabled(SDL_EVENT_CLIPBOARD_UPDATE, false);
}
struct ThreadCpuSample
{
uint64_t ticks = 0;
@@ -459,6 +547,8 @@ int main(int argc, char* argv[])
return 1;
}
disableUnusedSdlEvents();
SDL_Window* window = SDL_CreateWindow(
AppName,
1280,
@@ -1068,27 +1158,112 @@ int main(int argc, char* argv[])
perfSectionStartTicks =
SDL_GetPerformanceCounter();
while (SDL_PollEvent(&event))
{
ImGui_ImplSDL3_ProcessEvent(&event);
const uint64_t pumpStartTicks =
SDL_GetPerformanceCounter();
switch (event.type)
SDL_PumpEvents();
if (config.logPerf)
{
case SDL_EVENT_QUIT:
g_running = false;
break;
framePerf.eventPumpTicks +=
SDL_GetPerformanceCounter() -
pumpStartTicks;
}
}
case SDL_EVENT_WINDOW_RESIZED:
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
framebufferResized = true;
break;
constexpr int EventBatchSize = 64;
SDL_Event eventBatch[EventBatchSize];
case SDL_EVENT_KEY_DOWN:
if (event.key.key == SDLK_ESCAPE)
{
g_running = false;
while (true)
{
const uint64_t pollStartTicks =
SDL_GetPerformanceCounter();
const int eventCount = SDL_PeepEvents(
eventBatch,
EventBatchSize,
SDL_GETEVENT,
SDL_EVENT_FIRST,
SDL_EVENT_LAST
);
if (eventCount <= 0)
{
if (config.logPerf)
{
framePerf.emptyPollTicks +=
SDL_GetPerformanceCounter() -
pollStartTicks;
}
break;
}
if (config.logPerf)
{
const uint64_t pollTicks =
SDL_GetPerformanceCounter() -
pollStartTicks;
framePerf.eventPollTicks += pollTicks;
if (pollTicks > framePerf.maxEventPollTicks)
{
framePerf.maxEventPollTicks = pollTicks;
framePerf.maxPollEventType =
static_cast<uint32_t>(
eventBatch[0].type);
}
}
for (int eventIndex = 0;
eventIndex < eventCount;
++eventIndex)
{
event = eventBatch[eventIndex];
if (config.logPerf)
{
recordEventStats(framePerf, event);
}
const uint64_t processStartTicks =
SDL_GetPerformanceCounter();
ImGui_ImplSDL3_ProcessEvent(&event);
switch (event.type)
{
case SDL_EVENT_QUIT:
g_running = false;
break;
case SDL_EVENT_WINDOW_RESIZED:
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
framebufferResized = true;
break;
case SDL_EVENT_KEY_DOWN:
if (event.key.key == SDLK_ESCAPE)
{
g_running = false;
}
break;
}
if (config.logPerf)
{
const uint64_t processTicks =
SDL_GetPerformanceCounter() -
processStartTicks;
framePerf.eventProcessTicks += processTicks;
if (processTicks >
framePerf.maxEventProcessTicks)
{
framePerf.maxEventProcessTicks =
processTicks;
framePerf.maxProcessEventType =
static_cast<uint32_t>(event.type);
}
}
break;
}
}
@@ -1168,59 +1343,7 @@ int main(int argc, char* argv[])
continue;
}
// ---- frame timing ----
perfSectionStartTicks =
SDL_GetPerformanceCounter();
vkWaitForFences(
ctx.device(),
1,
&inFlightFence,
VK_TRUE,
UINT64_MAX
);
vkResetFences(
ctx.device(),
1,
&inFlightFence
);
if (config.logPerf)
{
const uint64_t elapsed =
SDL_GetPerformanceCounter() -
perfSectionStartTicks;
perfStats.submitPresentTicks += elapsed;
framePerf.fenceWaitTicks += elapsed;
framePerf.submitPresentTicks += elapsed;
}
++frameCounter;
if (config.logFps)
{
++framesSinceLastLog;
Uint64 now = SDL_GetTicks();
Uint64 elapsed = now - lastFpsLogTicks;
if (elapsed >= 1000)
{
double fps =
static_cast<double>(
framesSinceLastLog
) * 1000.0 /
static_cast<double>(elapsed);
std::cout << "FPS: " << fps
<< std::endl;
framesSinceLastLog = 0;
lastFpsLogTicks = now;
}
}
// ---- update feed pixels ----
// ---- read feeds (overlap with GPU) ----
std::fill(
feedUploadNeeded.begin(),
@@ -1328,6 +1451,60 @@ int main(int argc, char* argv[])
pendingUploadNeeded[i] = true;
}
// ---- fence wait (now after CPU work) ----
perfSectionStartTicks =
SDL_GetPerformanceCounter();
vkWaitForFences(
ctx.device(),
1,
&inFlightFence,
VK_TRUE,
UINT64_MAX
);
vkResetFences(
ctx.device(),
1,
&inFlightFence
);
if (config.logPerf)
{
const uint64_t elapsed =
SDL_GetPerformanceCounter() -
perfSectionStartTicks;
perfStats.submitPresentTicks += elapsed;
framePerf.fenceWaitTicks += elapsed;
framePerf.submitPresentTicks += elapsed;
}
++frameCounter;
if (config.logFps)
{
++framesSinceLastLog;
Uint64 now = SDL_GetTicks();
Uint64 elapsed = now - lastFpsLogTicks;
if (elapsed >= 1000)
{
double fps =
static_cast<double>(
framesSinceLastLog
) * 1000.0 /
static_cast<double>(elapsed);
std::cout << "FPS: " << fps
<< std::endl;
framesSinceLastLog = 0;
lastFpsLogTicks = now;
}
}
// ---- stage uploads ----
const uint32_t maxV210Uploads =
config.maxV210UploadsPerFrame == 0
? feedCount
@@ -1861,7 +2038,43 @@ int main(int argc, char* argv[])
<< (currentFrameTicks * invMs)
<< "ms event="
<< (framePerf.eventTicks * invMs)
<< "ms fence="
<< "ms events="
<< framePerf.events
<< " pump="
<< (framePerf.eventPumpTicks * invMs)
<< "ms peep="
<< (framePerf.eventPollTicks * invMs)
<< "ms process="
<< (framePerf.eventProcessTicks * invMs)
<< "ms emptyPoll="
<< (framePerf.emptyPollTicks * invMs)
<< "ms maxPoll="
<< (framePerf.maxEventPollTicks * invMs)
<< "ms/type="
<< framePerf.maxPollEventType
<< " maxProcess="
<< (framePerf.maxEventProcessTicks * invMs)
<< "ms/type="
<< framePerf.maxProcessEventType
<< " win="
<< framePerf.windowEvents
<< " resize="
<< framePerf.resizeEvents
<< " motion="
<< framePerf.mouseMotionEvents
<< " button="
<< framePerf.mouseButtonEvents
<< " wheel="
<< framePerf.mouseWheelEvents
<< " key="
<< framePerf.keyboardEvents
<< " text="
<< framePerf.textEvents
<< " quit="
<< framePerf.quitEvents
<< " otherEvents="
<< framePerf.otherEvents
<< " fence="
<< (framePerf.fenceWaitTicks * invMs)
<< "ms feedRead="
<< (framePerf.feedReadTicks * invMs)