#include "HyprDebugOverlay.hpp" #include "../Compositor.hpp" void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float µs) { m_dLastRenderTimes.push_back(µs / 1000.f); if (m_dLastRenderTimes.size() > (long unsigned int)pMonitor->refreshRate) m_dLastRenderTimes.pop_front(); if (!m_pMonitor) m_pMonitor = pMonitor; } void CHyprMonitorDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float µs) { m_dLastRenderTimesNoOverlay.push_back(µs / 1000.f); if (m_dLastRenderTimesNoOverlay.size() > (long unsigned int)pMonitor->refreshRate) m_dLastRenderTimesNoOverlay.pop_front(); if (!m_pMonitor) m_pMonitor = pMonitor; } void CHyprMonitorDebugOverlay::frameData(CMonitor* pMonitor) { m_dLastFrametimes.push_back(std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - m_tpLastFrame).count() / 1000.f); if (m_dLastFrametimes.size() > (long unsigned int)pMonitor->refreshRate) m_dLastFrametimes.pop_front(); m_tpLastFrame = std::chrono::high_resolution_clock::now(); if (!m_pMonitor) m_pMonitor = pMonitor; } int CHyprMonitorDebugOverlay::draw(int offset) { if (!m_pMonitor) return 0; int yOffset = offset; cairo_text_extents_t cairoExtents; float maxX = 0; std::string text = ""; // get avg fps float avgFrametime = 0; for (auto& ft : m_dLastFrametimes) { avgFrametime += ft; } avgFrametime /= m_dLastFrametimes.size() == 0 ? 1 : m_dLastFrametimes.size(); float avgRenderTime = 0; for (auto& rt : m_dLastRenderTimes) { avgRenderTime += rt; } avgRenderTime /= m_dLastRenderTimes.size() == 0 ? 1 : m_dLastRenderTimes.size(); float avgRenderTimeNoOverlay = 0; for (auto& rt : m_dLastRenderTimesNoOverlay) { avgRenderTimeNoOverlay += rt; } avgRenderTimeNoOverlay /= m_dLastRenderTimes.size() == 0 ? 1 : m_dLastRenderTimes.size(); const float FPS = 1.f / (avgFrametime / 1000.f); // frametimes are in ms const float idealFPS = m_dLastFrametimes.size(); cairo_select_font_face(g_pDebugOverlay->m_pCairo, "Noto Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size(g_pDebugOverlay->m_pCairo, 10); cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 1.f, 1.f, 1.f); yOffset += 10; cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset); text = m_pMonitor->szName; cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str()); cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents); if (cairoExtents.width > maxX) maxX = cairoExtents.width; cairo_set_font_size(g_pDebugOverlay->m_pCairo, 16); if (FPS > idealFPS * 0.95f) cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 0.2f, 1.f, 0.2f, 1.f); else if (FPS > idealFPS * 0.8f) cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 1.f, 0.2f, 1.f); else cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 0.2f, 0.2f, 1.f); yOffset += 17; cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset); text = std::string(std::to_string((int)FPS) + " FPS"); cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str()); cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents); if (cairoExtents.width > maxX) maxX = cairoExtents.width; cairo_set_font_size(g_pDebugOverlay->m_pCairo, 10); cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 1.f, 1.f, 1.f); yOffset += 11; cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset); text = std::string("Avg Frametime: " + std::to_string((int)avgFrametime) + "." + std::to_string((int)(avgFrametime * 10.f) % 10) + "ms"); cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str()); cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents); if (cairoExtents.width > maxX) maxX = cairoExtents.width; yOffset += 11; cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset); text = std::string("Avg Rendertime: " + std::to_string((int)avgRenderTime) + "." + std::to_string((int)(avgRenderTime * 10.f) % 10) + "ms"); cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str()); cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents); if (cairoExtents.width > maxX) maxX = cairoExtents.width; yOffset += 11; cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset); text = std::string("Avg Rendertime (no overlay): " + std::to_string((int)avgRenderTimeNoOverlay) + "." + std::to_string((int)(avgRenderTimeNoOverlay * 10.f) % 10) + "ms"); cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str()); cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents); if (cairoExtents.width > maxX) maxX = cairoExtents.width; yOffset += 11; g_pHyprRenderer->damageBox(&m_wbLastDrawnBox); m_wbLastDrawnBox = {(int)g_pCompositor->m_vMonitors.front()->vecPosition.x, (int)g_pCompositor->m_vMonitors.front()->vecPosition.y + offset - 1, (int)maxX + 2, yOffset - offset + 2}; g_pHyprRenderer->damageBox(&m_wbLastDrawnBox); return yOffset - offset; } void CHyprDebugOverlay::renderData(CMonitor* pMonitor, float µs) { m_mMonitorOverlays[pMonitor].renderData(pMonitor, µs); } void CHyprDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float µs) { m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, µs); } void CHyprDebugOverlay::frameData(CMonitor* pMonitor) { m_mMonitorOverlays[pMonitor].frameData(pMonitor); } void CHyprDebugOverlay::draw() { const auto PMONITOR = g_pCompositor->m_vMonitors.front().get(); if (!m_pCairoSurface || !m_pCairo) { m_pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->vecSize.x, PMONITOR->vecSize.y); m_pCairo = cairo_create(m_pCairoSurface); } // clear the pixmap cairo_save(m_pCairo); cairo_set_operator(m_pCairo, CAIRO_OPERATOR_CLEAR); cairo_paint(m_pCairo); cairo_restore(m_pCairo); // draw the things int offsetY = 0; for (auto& m : g_pCompositor->m_vMonitors) { offsetY += m_mMonitorOverlays[m.get()].draw(offsetY); offsetY += 5; // for padding between mons } cairo_surface_flush(m_pCairoSurface); // copy the data to an OpenGL texture we have const auto DATA = cairo_image_surface_get_data(m_pCairoSurface); m_tTexture.allocate(); glBindTexture(GL_TEXTURE_2D, m_tTexture.m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); #ifndef GLES2 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); #endif glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecSize.x, PMONITOR->vecSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); wlr_box pMonBox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y}; g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 255.f); }